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 PPC Assembler 38 // Generates user mode instructions for the PPC architecture up 39 40 #ifndef V8_CODEGEN_PPC_ASSEMBLER_PPC_H_ 41 #define V8_CODEGEN_PPC_ASSEMBLER_PPC_H_ 42 43 #include <stdio.h> 44 #include <memory> 45 #include <vector> 46 47 #include "src/codegen/assembler.h" 48 #include "src/codegen/constant-pool.h" 49 #include "src/codegen/external-reference.h" 50 #include "src/codegen/label.h" 51 #include "src/codegen/ppc/constants-ppc.h" 52 #include "src/codegen/ppc/register-ppc.h" 53 #include "src/numbers/double.h" 54 #include "src/objects/smi.h" 55 56 namespace v8 { 57 namespace internal { 58 59 class SafepointTableBuilder; 60 61 // ----------------------------------------------------------------------------- 62 // Machine instruction Operands 63 64 // Class Operand represents a shifter operand in data processing instructions 65 class V8_EXPORT_PRIVATE Operand { 66 public: 67 // immediate 68 V8_INLINE explicit Operand(intptr_t immediate, 69 RelocInfo::Mode rmode = RelocInfo::NONE) rmode_(rmode)70 : rmode_(rmode) { 71 value_.immediate = immediate; 72 } Zero()73 V8_INLINE static Operand Zero() { return Operand(static_cast<intptr_t>(0)); } Operand(const ExternalReference & f)74 V8_INLINE explicit Operand(const ExternalReference& f) 75 : rmode_(RelocInfo::EXTERNAL_REFERENCE) { 76 value_.immediate = static_cast<intptr_t>(f.address()); 77 } 78 explicit Operand(Handle<HeapObject> handle); Operand(Smi value)79 V8_INLINE explicit Operand(Smi value) : rmode_(RelocInfo::NONE) { 80 value_.immediate = static_cast<intptr_t>(value.ptr()); 81 } 82 // rm 83 V8_INLINE explicit Operand(Register rm); 84 85 static Operand EmbeddedNumber(double number); // Smi or HeapNumber. 86 static Operand EmbeddedStringConstant(const StringConstantBase* str); 87 88 // Return true if this is a register operand. is_reg()89 V8_INLINE bool is_reg() const { return rm_.is_valid(); } 90 91 bool must_output_reloc_info(const Assembler* assembler) const; 92 immediate()93 inline intptr_t immediate() const { 94 DCHECK(IsImmediate()); 95 DCHECK(!IsHeapObjectRequest()); 96 return value_.immediate; 97 } IsImmediate()98 bool IsImmediate() const { return !rm_.is_valid(); } 99 heap_object_request()100 HeapObjectRequest heap_object_request() const { 101 DCHECK(IsHeapObjectRequest()); 102 return value_.heap_object_request; 103 } 104 rm()105 Register rm() const { return rm_; } 106 IsHeapObjectRequest()107 bool IsHeapObjectRequest() const { 108 DCHECK_IMPLIES(is_heap_object_request_, IsImmediate()); 109 DCHECK_IMPLIES(is_heap_object_request_, 110 rmode_ == RelocInfo::FULL_EMBEDDED_OBJECT || 111 rmode_ == RelocInfo::CODE_TARGET); 112 return is_heap_object_request_; 113 } 114 115 private: 116 Register rm_ = no_reg; 117 union Value { Value()118 Value() {} 119 HeapObjectRequest heap_object_request; // if is_heap_object_request_ 120 intptr_t immediate; // otherwise 121 } value_; // valid if rm_ == no_reg 122 bool is_heap_object_request_ = false; 123 124 RelocInfo::Mode rmode_; 125 126 friend class Assembler; 127 friend class MacroAssembler; 128 }; 129 130 // Class MemOperand represents a memory operand in load and store instructions 131 // On PowerPC we have base register + 16bit signed value 132 // Alternatively we can have a 16bit signed value immediate 133 class V8_EXPORT_PRIVATE MemOperand { 134 public: 135 explicit MemOperand(Register rn, int32_t offset = 0); 136 137 explicit MemOperand(Register ra, Register rb); 138 offset()139 int32_t offset() const { return offset_; } 140 141 // PowerPC - base register ra()142 Register ra() const { return ra_; } 143 rb()144 Register rb() const { return rb_; } 145 146 private: 147 Register ra_; // base 148 int32_t offset_; // offset 149 Register rb_; // index 150 151 friend class Assembler; 152 }; 153 154 class DeferredRelocInfo { 155 public: DeferredRelocInfo()156 DeferredRelocInfo() {} DeferredRelocInfo(int position,RelocInfo::Mode rmode,intptr_t data)157 DeferredRelocInfo(int position, RelocInfo::Mode rmode, intptr_t data) 158 : position_(position), rmode_(rmode), data_(data) {} 159 position()160 int position() const { return position_; } rmode()161 RelocInfo::Mode rmode() const { return rmode_; } data()162 intptr_t data() const { return data_; } 163 164 private: 165 int position_; 166 RelocInfo::Mode rmode_; 167 intptr_t data_; 168 }; 169 170 class Assembler : public AssemblerBase { 171 public: 172 // Create an assembler. Instructions and relocation information are emitted 173 // into a buffer, with the instructions starting from the beginning and the 174 // relocation information starting from the end of the buffer. See CodeDesc 175 // for a detailed comment on the layout (globals.h). 176 // 177 // If the provided buffer is nullptr, the assembler allocates and grows its 178 // own buffer. Otherwise it takes ownership of the provided buffer. 179 explicit Assembler(const AssemblerOptions&, 180 std::unique_ptr<AssemblerBuffer> = {}); 181 ~Assembler()182 virtual ~Assembler() {} 183 184 // GetCode emits any pending (non-emitted) code and fills the descriptor desc. 185 static constexpr int kNoHandlerTable = 0; 186 static constexpr SafepointTableBuilder* kNoSafepointTable = nullptr; 187 void GetCode(Isolate* isolate, CodeDesc* desc, 188 SafepointTableBuilder* safepoint_table_builder, 189 int handler_table_offset); 190 191 // Convenience wrapper for code without safepoint or handler tables. GetCode(Isolate * isolate,CodeDesc * desc)192 void GetCode(Isolate* isolate, CodeDesc* desc) { 193 GetCode(isolate, desc, kNoSafepointTable, kNoHandlerTable); 194 } 195 MaybeEmitOutOfLineConstantPool()196 void MaybeEmitOutOfLineConstantPool() { EmitConstantPool(); } 197 198 // Label operations & relative jumps (PPUM Appendix D) 199 // 200 // Takes a branch opcode (cc) and a label (L) and generates 201 // either a backward branch or a forward branch and links it 202 // to the label fixup chain. Usage: 203 // 204 // Label L; // unbound label 205 // j(cc, &L); // forward branch to unbound label 206 // bind(&L); // bind label to the current pc 207 // j(cc, &L); // backward branch to bound label 208 // bind(&L); // illegal: a label may be bound only once 209 // 210 // Note: The same Label can be used for forward and backward branches 211 // but it may be bound only once. 212 213 void bind(Label* L); // binds an unbound label L to the current code position 214 215 // Links a label at the current pc_offset(). If already bound, returns the 216 // bound position. If already linked, returns the position of the prior link. 217 // Otherwise, returns the current pc_offset(). 218 int link(Label* L); 219 220 // Determines if Label is bound and near enough so that a single 221 // branch instruction can be used to reach it. 222 bool is_near(Label* L, Condition cond); 223 224 // Returns the branch offset to the given label from the current code position 225 // Links the label to the current position if it is still unbound branch_offset(Label * L)226 int branch_offset(Label* L) { 227 if (L->is_unused() && !trampoline_emitted_) { 228 TrackBranch(); 229 } 230 return link(L) - pc_offset(); 231 } 232 233 V8_INLINE static bool IsConstantPoolLoadStart( 234 Address pc, ConstantPoolEntry::Access* access = nullptr); 235 V8_INLINE static bool IsConstantPoolLoadEnd( 236 Address pc, ConstantPoolEntry::Access* access = nullptr); 237 V8_INLINE static int GetConstantPoolOffset(Address pc, 238 ConstantPoolEntry::Access access, 239 ConstantPoolEntry::Type type); 240 V8_INLINE void PatchConstantPoolAccessInstruction( 241 int pc_offset, int offset, ConstantPoolEntry::Access access, 242 ConstantPoolEntry::Type type); 243 244 // Return the address in the constant pool of the code target address used by 245 // the branch/call instruction at pc, or the object in a mov. 246 V8_INLINE static Address target_constant_pool_address_at( 247 Address pc, Address constant_pool, ConstantPoolEntry::Access access, 248 ConstantPoolEntry::Type type); 249 250 // Read/Modify the code target address in the branch/call instruction at pc. 251 // The isolate argument is unused (and may be nullptr) when skipping flushing. 252 V8_INLINE static Address target_address_at(Address pc, Address constant_pool); 253 V8_INLINE static void set_target_address_at( 254 Address pc, Address constant_pool, Address target, 255 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 256 257 // Read/Modify the code target address in the branch/call instruction at pc. 258 inline static Tagged_t target_compressed_address_at(Address pc, 259 Address constant_pool); 260 inline static void set_target_compressed_address_at( 261 Address pc, Address constant_pool, Tagged_t target, 262 ICacheFlushMode icache_flush_mode = FLUSH_ICACHE_IF_NEEDED); 263 264 inline Handle<Object> code_target_object_handle_at(Address pc, 265 Address constant_pool); 266 inline Handle<HeapObject> compressed_embedded_object_handle_at( 267 Address pc, Address constant_pool); 268 269 // This sets the branch destination. 270 // This is for calls and branches within generated code. 271 inline static void deserialization_set_special_target_at( 272 Address instruction_payload, Code code, Address target); 273 274 // Get the size of the special target encoded at 'instruction_payload'. 275 inline static int deserialization_special_target_size( 276 Address instruction_payload); 277 278 // This sets the internal reference at the pc. 279 inline static void deserialization_set_target_internal_reference_at( 280 Address pc, Address target, 281 RelocInfo::Mode mode = RelocInfo::INTERNAL_REFERENCE); 282 283 // Here we are patching the address in the LUI/ORI instruction pair. 284 // These values are used in the serialization process and must be zero for 285 // PPC platform, as Code, Embedded Object or External-reference pointers 286 // are split across two consecutive instructions and don't exist separately 287 // in the code, so the serializer should not step forwards in memory after 288 // a target is resolved and written. 289 static constexpr int kSpecialTargetSize = 0; 290 291 // Number of instructions to load an address via a mov sequence. 292 #if V8_TARGET_ARCH_PPC64 293 static constexpr int kMovInstructionsConstantPool = 1; 294 static constexpr int kMovInstructionsNoConstantPool = 5; 295 #if defined(V8_PPC_TAGGING_OPT) 296 static constexpr int kTaggedLoadInstructions = 1; 297 #else 298 static constexpr int kTaggedLoadInstructions = 2; 299 #endif 300 #else 301 static constexpr int kMovInstructionsConstantPool = 1; 302 static constexpr int kMovInstructionsNoConstantPool = 2; 303 static constexpr int kTaggedLoadInstructions = 1; 304 #endif 305 static constexpr int kMovInstructions = FLAG_enable_embedded_constant_pool 306 ? kMovInstructionsConstantPool 307 : kMovInstructionsNoConstantPool; 308 encode_crbit(const CRegister & cr,enum CRBit crbit)309 static inline int encode_crbit(const CRegister& cr, enum CRBit crbit) { 310 return ((cr.code() * CRWIDTH) + crbit); 311 } 312 313 #define DECLARE_PPC_X_INSTRUCTIONS_A_FORM(name, instr_name, instr_value) \ 314 inline void name(const Register rt, const Register ra, const Register rb, \ 315 const RCBit rc = LeaveRC) { \ 316 x_form(instr_name, rt, ra, rb, rc); \ 317 } 318 319 #define DECLARE_PPC_X_INSTRUCTIONS_B_FORM(name, instr_name, instr_value) \ 320 inline void name(const Register ra, const Register rs, const Register rb, \ 321 const RCBit rc = LeaveRC) { \ 322 x_form(instr_name, rs, ra, rb, rc); \ 323 } 324 325 #define DECLARE_PPC_X_INSTRUCTIONS_C_FORM(name, instr_name, instr_value) \ 326 inline void name(const Register dst, const Register src, \ 327 const RCBit rc = LeaveRC) { \ 328 x_form(instr_name, src, dst, r0, rc); \ 329 } 330 331 #define DECLARE_PPC_X_INSTRUCTIONS_D_FORM(name, instr_name, instr_value) \ 332 template <class R> \ 333 inline void name(const R rt, const Register ra, const Register rb, \ 334 const RCBit rc = LeaveRC) { \ 335 x_form(instr_name, rt.code(), ra.code(), rb.code(), rc); \ 336 } \ 337 template <class R> \ 338 inline void name(const R dst, const MemOperand& src) { \ 339 name(dst, src.ra(), src.rb()); \ 340 } 341 342 #define DECLARE_PPC_X_INSTRUCTIONS_E_FORM(name, instr_name, instr_value) \ 343 inline void name(const Register dst, const Register src, const int sh, \ 344 const RCBit rc = LeaveRC) { \ 345 x_form(instr_name, src.code(), dst.code(), sh, rc); \ 346 } 347 348 #define DECLARE_PPC_X_INSTRUCTIONS_F_FORM(name, instr_name, instr_value) \ 349 inline void name(const Register src1, const Register src2, \ 350 const CRegister cr = cr7, const RCBit rc = LeaveRC) { \ 351 x_form(instr_name, cr, src1, src2, rc); \ 352 } \ 353 inline void name##w(const Register src1, const Register src2, \ 354 const CRegister cr = cr7, const RCBit rc = LeaveRC) { \ 355 x_form(instr_name, cr.code() * B2, src1.code(), src2.code(), LeaveRC); \ 356 } 357 358 #define DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM(name, instr_name, instr_value) \ 359 inline void name(const Register dst, const MemOperand& src) { \ 360 x_form(instr_name, src.ra(), dst, src.rb(), SetEH); \ 361 } 362 #define DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM(name, instr_name, instr_value) \ 363 inline void name(const Register dst, const MemOperand& src) { \ 364 DCHECK(src.ra_ != r0); \ 365 x_form(instr_name, src.ra(), dst, src.rb(), SetEH); \ 366 } 367 x_form(Instr instr,int f1,int f2,int f3,int rc)368 inline void x_form(Instr instr, int f1, int f2, int f3, int rc) { 369 emit(instr | f1 * B21 | f2 * B16 | f3 * B11 | rc); 370 } x_form(Instr instr,Register rs,Register ra,Register rb,RCBit rc)371 inline void x_form(Instr instr, Register rs, Register ra, Register rb, 372 RCBit rc) { 373 emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | rc); 374 } 375 inline void x_form(Instr instr, Register ra, Register rs, Register rb, 376 EHBit eh = SetEH) { 377 emit(instr | rs.code() * B21 | ra.code() * B16 | rb.code() * B11 | eh); 378 } x_form(Instr instr,CRegister cr,Register s1,Register s2,RCBit rc)379 inline void x_form(Instr instr, CRegister cr, Register s1, Register s2, 380 RCBit rc) { 381 #if V8_TARGET_ARCH_PPC64 382 int L = 1; 383 #else 384 int L = 0; 385 #endif 386 emit(instr | cr.code() * B23 | L * B21 | s1.code() * B16 | s2.code() * B11 | 387 rc); 388 } 389 390 PPC_X_OPCODE_A_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_A_FORM) PPC_X_OPCODE_B_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_B_FORM)391 PPC_X_OPCODE_B_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_B_FORM) 392 PPC_X_OPCODE_C_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_C_FORM) 393 PPC_X_OPCODE_D_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_D_FORM) 394 PPC_X_OPCODE_E_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_E_FORM) 395 PPC_X_OPCODE_F_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_F_FORM) 396 PPC_X_OPCODE_EH_S_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM) 397 PPC_X_OPCODE_EH_L_FORM_LIST(DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM) 398 399 inline void notx(Register dst, Register src, RCBit rc = LeaveRC) { 400 nor(dst, src, src, rc); 401 } lwax(Register rt,const MemOperand & src)402 inline void lwax(Register rt, const MemOperand& src) { 403 #if V8_TARGET_ARCH_PPC64 404 Register ra = src.ra(); 405 Register rb = src.rb(); 406 DCHECK(ra != r0); 407 x_form(LWAX, rt, ra, rb, LeaveRC); 408 #else 409 lwzx(rt, src); 410 #endif 411 } 412 inline void extsw(Register rs, Register ra, RCBit rc = LeaveRC) { 413 #if V8_TARGET_ARCH_PPC64 414 emit(EXT2 | EXTSW | ra.code() * B21 | rs.code() * B16 | rc); 415 #else 416 // nop on 32-bit 417 DCHECK(rs == ra && rc == LeaveRC); 418 #endif 419 } 420 421 #undef DECLARE_PPC_X_INSTRUCTIONS_A_FORM 422 #undef DECLARE_PPC_X_INSTRUCTIONS_B_FORM 423 #undef DECLARE_PPC_X_INSTRUCTIONS_C_FORM 424 #undef DECLARE_PPC_X_INSTRUCTIONS_D_FORM 425 #undef DECLARE_PPC_X_INSTRUCTIONS_E_FORM 426 #undef DECLARE_PPC_X_INSTRUCTIONS_F_FORM 427 #undef DECLARE_PPC_X_INSTRUCTIONS_EH_S_FORM 428 #undef DECLARE_PPC_X_INSTRUCTIONS_EH_L_FORM 429 430 #define DECLARE_PPC_XX2_INSTRUCTIONS(name, instr_name, instr_value) \ 431 inline void name(const Simd128Register rt, const Simd128Register rb) { \ 432 xx2_form(instr_name, rt, rb); \ 433 } 434 xx2_form(Instr instr,Simd128Register t,Simd128Register b)435 inline void xx2_form(Instr instr, Simd128Register t, Simd128Register b) { 436 // Using VR (high VSR) registers. 437 int BX = 1; 438 int TX = 1; 439 440 emit(instr | (t.code() & 0x1F) * B21 | (b.code() & 0x1F) * B11 | BX * B1 | 441 TX); 442 } 443 PPC_XX2_OPCODE_A_FORM_LIST(DECLARE_PPC_XX2_INSTRUCTIONS)444 PPC_XX2_OPCODE_A_FORM_LIST(DECLARE_PPC_XX2_INSTRUCTIONS) 445 #undef DECLARE_PPC_XX2_INSTRUCTIONS 446 447 #define DECLARE_PPC_XX3_INSTRUCTIONS(name, instr_name, instr_value) \ 448 inline void name(const DoubleRegister rt, const DoubleRegister ra, \ 449 const DoubleRegister rb) { \ 450 xx3_form(instr_name, rt, ra, rb); \ 451 } 452 453 inline void xx3_form(Instr instr, DoubleRegister t, DoubleRegister a, 454 DoubleRegister b) { 455 // Using VR (high VSR) registers. 456 int AX = 1; 457 int BX = 1; 458 int TX = 1; 459 460 emit(instr | (t.code() & 0x1F) * B21 | (a.code() & 0x1F) * B16 | 461 (b.code() & 0x1F) * B11 | AX * B2 | BX * B1 | TX); 462 } 463 PPC_XX3_OPCODE_LIST(DECLARE_PPC_XX3_INSTRUCTIONS)464 PPC_XX3_OPCODE_LIST(DECLARE_PPC_XX3_INSTRUCTIONS) 465 #undef DECLARE_PPC_XX3_INSTRUCTIONS 466 467 #define DECLARE_PPC_VX_INSTRUCTIONS_A_FORM(name, instr_name, instr_value) \ 468 inline void name(const Simd128Register rt, const Simd128Register rb, \ 469 const Operand& imm) { \ 470 vx_form(instr_name, rt, rb, imm); \ 471 } 472 #define DECLARE_PPC_VX_INSTRUCTIONS_B_FORM(name, instr_name, instr_value) \ 473 inline void name(const Simd128Register rt, const Simd128Register ra, \ 474 const Simd128Register rb) { \ 475 vx_form(instr_name, rt, ra, rb); \ 476 } 477 #define DECLARE_PPC_VX_INSTRUCTIONS_C_FORM(name, instr_name, instr_value) \ 478 inline void name(const Simd128Register rt, const Simd128Register rb) { \ 479 vx_form(instr_name, rt, rb); \ 480 } 481 482 inline void vx_form(Instr instr, Simd128Register rt, Simd128Register rb, 483 const Operand& imm) { 484 emit(instr | rt.code() * B21 | imm.immediate() * B16 | rb.code() * B11); 485 } vx_form(Instr instr,Simd128Register rt,Simd128Register ra,Simd128Register rb)486 inline void vx_form(Instr instr, Simd128Register rt, Simd128Register ra, 487 Simd128Register rb) { 488 emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11); 489 } vx_form(Instr instr,Simd128Register rt,Simd128Register rb)490 inline void vx_form(Instr instr, Simd128Register rt, Simd128Register rb) { 491 emit(instr | rt.code() * B21 | rb.code() * B11); 492 } 493 494 PPC_VX_OPCODE_A_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_A_FORM) PPC_VX_OPCODE_B_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_B_FORM)495 PPC_VX_OPCODE_B_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_B_FORM) 496 PPC_VX_OPCODE_C_FORM_LIST(DECLARE_PPC_VX_INSTRUCTIONS_C_FORM) 497 #undef DECLARE_PPC_VX_INSTRUCTIONS_A_FORM 498 #undef DECLARE_PPC_VX_INSTRUCTIONS_B_FORM 499 #undef DECLARE_PPC_VX_INSTRUCTIONS_C_FORM 500 501 #define DECLARE_PPC_VA_INSTRUCTIONS_A_FORM(name, instr_name, instr_value) \ 502 inline void name(const Simd128Register rt, const Simd128Register ra, \ 503 const Simd128Register rb, const Simd128Register rc) { \ 504 va_form(instr_name, rt, ra, rb, rc); \ 505 } 506 507 inline void va_form(Instr instr, Simd128Register rt, Simd128Register ra, 508 Simd128Register rb, Simd128Register rc) { 509 emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | 510 rc.code() * B6); 511 } 512 PPC_VA_OPCODE_A_FORM_LIST(DECLARE_PPC_VA_INSTRUCTIONS_A_FORM)513 PPC_VA_OPCODE_A_FORM_LIST(DECLARE_PPC_VA_INSTRUCTIONS_A_FORM) 514 #undef DECLARE_PPC_VA_INSTRUCTIONS_A_FORM 515 516 #define DECLARE_PPC_VC_INSTRUCTIONS(name, instr_name, instr_value) \ 517 inline void name(const Simd128Register rt, const Simd128Register ra, \ 518 const Simd128Register rb, const RCBit rc = LeaveRC) { \ 519 vc_form(instr_name, rt, ra, rb, rc); \ 520 } 521 522 inline void vc_form(Instr instr, Simd128Register rt, Simd128Register ra, 523 Simd128Register rb, int rc) { 524 emit(instr | rt.code() * B21 | ra.code() * B16 | rb.code() * B11 | 525 rc * B10); 526 } 527 PPC_VC_OPCODE_LIST(DECLARE_PPC_VC_INSTRUCTIONS)528 PPC_VC_OPCODE_LIST(DECLARE_PPC_VC_INSTRUCTIONS) 529 #undef DECLARE_PPC_VC_INSTRUCTIONS 530 531 RegList* GetScratchRegisterList() { return &scratch_register_list_; } 532 // --------------------------------------------------------------------------- 533 // Code generation 534 535 // Insert the smallest number of nop instructions 536 // possible to align the pc offset to a multiple 537 // of m. m must be a power of 2 (>= 4). 538 void Align(int m); 539 // Insert the smallest number of zero bytes possible to align the pc offset 540 // to a mulitple of m. m must be a power of 2 (>= 2). 541 void DataAlign(int m); 542 // Aligns code to something that's optimal for a jump target for the platform. 543 void CodeTargetAlign(); 544 545 // Branch instructions 546 void bclr(BOfield bo, int condition_bit, LKBit lk); 547 void blr(); 548 void bc(int branch_offset, BOfield bo, int condition_bit, LKBit lk = LeaveLK); 549 void b(int branch_offset, LKBit lk); 550 551 void bcctr(BOfield bo, int condition_bit, LKBit lk); 552 void bctr(); 553 void bctrl(); 554 555 // Convenience branch instructions using labels 556 void b(Label* L, LKBit lk = LeaveLK) { b(branch_offset(L), lk); } 557 cmpi_optimization(CRegister cr)558 inline CRegister cmpi_optimization(CRegister cr) { 559 // Check whether the branch is preceded by an optimizable cmpi against 0. 560 // The cmpi can be deleted if it is also preceded by an instruction that 561 // sets the register used by the compare and supports a dot form. 562 unsigned int sradi_mask = kOpcodeMask | kExt2OpcodeVariant2Mask; 563 unsigned int srawi_mask = kOpcodeMask | kExt2OpcodeMask; 564 int pos = pc_offset(); 565 int cmpi_pos = pc_offset() - kInstrSize; 566 567 if (cmpi_pos > 0 && optimizable_cmpi_pos_ == cmpi_pos && 568 cmpi_cr_.code() == cr.code() && last_bound_pos_ != pos) { 569 int xpos = cmpi_pos - kInstrSize; 570 int xinstr = instr_at(xpos); 571 int cmpi_ra = (instr_at(cmpi_pos) & 0x1f0000) >> 16; 572 // ra is at the same bit position for the three cases below. 573 int ra = (xinstr & 0x1f0000) >> 16; 574 if (cmpi_ra == ra) { 575 if ((xinstr & sradi_mask) == (EXT2 | SRADIX)) { 576 cr = cr0; 577 instr_at_put(xpos, xinstr | SetRC); 578 pc_ -= kInstrSize; 579 } else if ((xinstr & srawi_mask) == (EXT2 | SRAWIX)) { 580 cr = cr0; 581 instr_at_put(xpos, xinstr | SetRC); 582 pc_ -= kInstrSize; 583 } else if ((xinstr & kOpcodeMask) == ANDIx) { 584 cr = cr0; 585 pc_ -= kInstrSize; 586 // nothing to do here since andi. records. 587 } 588 // didn't match one of the above, must keep cmpwi. 589 } 590 } 591 return cr; 592 } 593 594 void bc_short(Condition cond, Label* L, CRegister cr = cr7, 595 LKBit lk = LeaveLK) { 596 DCHECK(cond != al); 597 DCHECK(cr.code() >= 0 && cr.code() <= 7); 598 599 cr = cmpi_optimization(cr); 600 601 int b_offset = branch_offset(L); 602 603 switch (cond) { 604 case eq: 605 bc(b_offset, BT, encode_crbit(cr, CR_EQ), lk); 606 break; 607 case ne: 608 bc(b_offset, BF, encode_crbit(cr, CR_EQ), lk); 609 break; 610 case gt: 611 bc(b_offset, BT, encode_crbit(cr, CR_GT), lk); 612 break; 613 case le: 614 bc(b_offset, BF, encode_crbit(cr, CR_GT), lk); 615 break; 616 case lt: 617 bc(b_offset, BT, encode_crbit(cr, CR_LT), lk); 618 break; 619 case ge: 620 bc(b_offset, BF, encode_crbit(cr, CR_LT), lk); 621 break; 622 case unordered: 623 bc(b_offset, BT, encode_crbit(cr, CR_FU), lk); 624 break; 625 case ordered: 626 bc(b_offset, BF, encode_crbit(cr, CR_FU), lk); 627 break; 628 case overflow: 629 bc(b_offset, BT, encode_crbit(cr, CR_SO), lk); 630 break; 631 case nooverflow: 632 bc(b_offset, BF, encode_crbit(cr, CR_SO), lk); 633 break; 634 default: 635 UNIMPLEMENTED(); 636 } 637 } 638 639 void bclr(Condition cond, CRegister cr = cr7, LKBit lk = LeaveLK) { 640 DCHECK(cond != al); 641 DCHECK(cr.code() >= 0 && cr.code() <= 7); 642 643 cr = cmpi_optimization(cr); 644 645 switch (cond) { 646 case eq: 647 bclr(BT, encode_crbit(cr, CR_EQ), lk); 648 break; 649 case ne: 650 bclr(BF, encode_crbit(cr, CR_EQ), lk); 651 break; 652 case gt: 653 bclr(BT, encode_crbit(cr, CR_GT), lk); 654 break; 655 case le: 656 bclr(BF, encode_crbit(cr, CR_GT), lk); 657 break; 658 case lt: 659 bclr(BT, encode_crbit(cr, CR_LT), lk); 660 break; 661 case ge: 662 bclr(BF, encode_crbit(cr, CR_LT), lk); 663 break; 664 case unordered: 665 bclr(BT, encode_crbit(cr, CR_FU), lk); 666 break; 667 case ordered: 668 bclr(BF, encode_crbit(cr, CR_FU), lk); 669 break; 670 case overflow: 671 bclr(BT, encode_crbit(cr, CR_SO), lk); 672 break; 673 case nooverflow: 674 bclr(BF, encode_crbit(cr, CR_SO), lk); 675 break; 676 default: 677 UNIMPLEMENTED(); 678 } 679 } 680 681 void isel(Register rt, Register ra, Register rb, int cb); 682 void isel(Condition cond, Register rt, Register ra, Register rb, 683 CRegister cr = cr7) { 684 DCHECK(cond != al); 685 DCHECK(cr.code() >= 0 && cr.code() <= 7); 686 687 cr = cmpi_optimization(cr); 688 689 switch (cond) { 690 case eq: 691 isel(rt, ra, rb, encode_crbit(cr, CR_EQ)); 692 break; 693 case ne: 694 isel(rt, rb, ra, encode_crbit(cr, CR_EQ)); 695 break; 696 case gt: 697 isel(rt, ra, rb, encode_crbit(cr, CR_GT)); 698 break; 699 case le: 700 isel(rt, rb, ra, encode_crbit(cr, CR_GT)); 701 break; 702 case lt: 703 isel(rt, ra, rb, encode_crbit(cr, CR_LT)); 704 break; 705 case ge: 706 isel(rt, rb, ra, encode_crbit(cr, CR_LT)); 707 break; 708 case unordered: 709 isel(rt, ra, rb, encode_crbit(cr, CR_FU)); 710 break; 711 case ordered: 712 isel(rt, rb, ra, encode_crbit(cr, CR_FU)); 713 break; 714 case overflow: 715 isel(rt, ra, rb, encode_crbit(cr, CR_SO)); 716 break; 717 case nooverflow: 718 isel(rt, rb, ra, encode_crbit(cr, CR_SO)); 719 break; 720 default: 721 UNIMPLEMENTED(); 722 } 723 } 724 725 void b(Condition cond, Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 726 if (cond == al) { 727 b(L, lk); 728 return; 729 } 730 731 if ((L->is_bound() && is_near(L, cond)) || !is_trampoline_emitted()) { 732 bc_short(cond, L, cr, lk); 733 return; 734 } 735 736 Label skip; 737 Condition neg_cond = NegateCondition(cond); 738 bc_short(neg_cond, &skip, cr); 739 b(L, lk); 740 bind(&skip); 741 } 742 743 void bne(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 744 b(ne, L, cr, lk); 745 } 746 void beq(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 747 b(eq, L, cr, lk); 748 } 749 void blt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 750 b(lt, L, cr, lk); 751 } 752 void bge(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 753 b(ge, L, cr, lk); 754 } 755 void ble(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 756 b(le, L, cr, lk); 757 } 758 void bgt(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 759 b(gt, L, cr, lk); 760 } 761 void bunordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 762 b(unordered, L, cr, lk); 763 } 764 void bordered(Label* L, CRegister cr = cr7, LKBit lk = LeaveLK) { 765 b(ordered, L, cr, lk); 766 } 767 void boverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) { 768 b(overflow, L, cr, lk); 769 } 770 void bnooverflow(Label* L, CRegister cr = cr0, LKBit lk = LeaveLK) { 771 b(nooverflow, L, cr, lk); 772 } 773 774 // Decrement CTR; branch if CTR != 0 775 void bdnz(Label* L, LKBit lk = LeaveLK) { 776 bc(branch_offset(L), DCBNZ, 0, lk); 777 } 778 779 // Data-processing instructions 780 781 void sub(Register dst, Register src1, Register src2, OEBit s = LeaveOE, 782 RCBit r = LeaveRC); 783 784 void subc(Register dst, Register src1, Register src2, OEBit s = LeaveOE, 785 RCBit r = LeaveRC); 786 void sube(Register dst, Register src1, Register src2, OEBit s = LeaveOE, 787 RCBit r = LeaveRC); 788 789 void subfic(Register dst, Register src, const Operand& imm); 790 791 void add(Register dst, Register src1, Register src2, OEBit s = LeaveOE, 792 RCBit r = LeaveRC); 793 794 void addc(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 795 RCBit r = LeaveRC); 796 void adde(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 797 RCBit r = LeaveRC); 798 void addze(Register dst, Register src1, OEBit o = LeaveOE, RCBit r = LeaveRC); 799 800 void mullw(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 801 RCBit r = LeaveRC); 802 803 void mulhw(Register dst, Register src1, Register src2, RCBit r = LeaveRC); 804 void mulhwu(Register dst, Register src1, Register src2, RCBit r = LeaveRC); 805 806 void divw(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 807 RCBit r = LeaveRC); 808 void divwu(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 809 RCBit r = LeaveRC); 810 811 void addi(Register dst, Register src, const Operand& imm); 812 void addis(Register dst, Register src, const Operand& imm); 813 void addic(Register dst, Register src, const Operand& imm); 814 815 void andi(Register ra, Register rs, const Operand& imm); 816 void andis(Register ra, Register rs, const Operand& imm); 817 void ori(Register dst, Register src, const Operand& imm); 818 void oris(Register dst, Register src, const Operand& imm); 819 void xori(Register dst, Register src, const Operand& imm); 820 void xoris(Register ra, Register rs, const Operand& imm); 821 void cmpi(Register src1, const Operand& src2, CRegister cr = cr7); 822 void cmpli(Register src1, const Operand& src2, CRegister cr = cr7); 823 void cmpwi(Register src1, const Operand& src2, CRegister cr = cr7); 824 void cmplwi(Register src1, const Operand& src2, CRegister cr = cr7); 825 void li(Register dst, const Operand& src); 826 void lis(Register dst, const Operand& imm); 827 void mr(Register dst, Register src); 828 829 void lbz(Register dst, const MemOperand& src); 830 void lhz(Register dst, const MemOperand& src); 831 void lha(Register dst, const MemOperand& src); 832 void lwz(Register dst, const MemOperand& src); 833 void lwzu(Register dst, const MemOperand& src); 834 void lwa(Register dst, const MemOperand& src); 835 void stb(Register dst, const MemOperand& src); 836 void sth(Register dst, const MemOperand& src); 837 void stw(Register dst, const MemOperand& src); 838 void stwu(Register dst, const MemOperand& src); 839 void neg(Register rt, Register ra, OEBit o = LeaveOE, RCBit c = LeaveRC); 840 841 #if V8_TARGET_ARCH_PPC64 842 void ld(Register rd, const MemOperand& src); 843 void ldu(Register rd, const MemOperand& src); 844 void std(Register rs, const MemOperand& src); 845 void stdu(Register rs, const MemOperand& src); 846 void rldic(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC); 847 void rldicl(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC); 848 void rldcl(Register ra, Register rs, Register rb, int mb, RCBit r = LeaveRC); 849 void rldicr(Register dst, Register src, int sh, int me, RCBit r = LeaveRC); 850 void rldimi(Register dst, Register src, int sh, int mb, RCBit r = LeaveRC); 851 void sldi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC); 852 void srdi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC); 853 void clrrdi(Register dst, Register src, const Operand& val, 854 RCBit rc = LeaveRC); 855 void clrldi(Register dst, Register src, const Operand& val, 856 RCBit rc = LeaveRC); 857 void sradi(Register ra, Register rs, int sh, RCBit r = LeaveRC); 858 void rotld(Register ra, Register rs, Register rb, RCBit r = LeaveRC); 859 void rotldi(Register ra, Register rs, int sh, RCBit r = LeaveRC); 860 void rotrdi(Register ra, Register rs, int sh, RCBit r = LeaveRC); 861 void mulld(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 862 RCBit r = LeaveRC); 863 void divd(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 864 RCBit r = LeaveRC); 865 void divdu(Register dst, Register src1, Register src2, OEBit o = LeaveOE, 866 RCBit r = LeaveRC); 867 #endif 868 869 void rlwinm(Register ra, Register rs, int sh, int mb, int me, 870 RCBit rc = LeaveRC); 871 void rlwimi(Register ra, Register rs, int sh, int mb, int me, 872 RCBit rc = LeaveRC); 873 void rlwnm(Register ra, Register rs, Register rb, int mb, int me, 874 RCBit rc = LeaveRC); 875 void slwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC); 876 void srwi(Register dst, Register src, const Operand& val, RCBit rc = LeaveRC); 877 void clrrwi(Register dst, Register src, const Operand& val, 878 RCBit rc = LeaveRC); 879 void clrlwi(Register dst, Register src, const Operand& val, 880 RCBit rc = LeaveRC); 881 void rotlw(Register ra, Register rs, Register rb, RCBit r = LeaveRC); 882 void rotlwi(Register ra, Register rs, int sh, RCBit r = LeaveRC); 883 void rotrwi(Register ra, Register rs, int sh, RCBit r = LeaveRC); 884 885 void subi(Register dst, Register src1, const Operand& src2); 886 887 void mov(Register dst, const Operand& src); 888 void bitwise_mov(Register dst, intptr_t value); 889 void bitwise_mov32(Register dst, int32_t value); 890 void bitwise_add32(Register dst, Register src, int32_t value); 891 892 // Load the position of the label relative to the generated code object 893 // pointer in a register. 894 void mov_label_offset(Register dst, Label* label); 895 896 // dst = base + label position + delta 897 void add_label_offset(Register dst, Register base, Label* label, 898 int delta = 0); 899 900 // Load the address of the label in a register and associate with an 901 // internal reference relocation. 902 void mov_label_addr(Register dst, Label* label); 903 904 // Emit the address of the label (i.e. a jump table entry) and associate with 905 // an internal reference relocation. 906 void emit_label_addr(Label* label); 907 908 // Multiply instructions 909 void mul(Register dst, Register src1, Register src2, OEBit s = LeaveOE, 910 RCBit r = LeaveRC); 911 912 // Miscellaneous arithmetic instructions 913 914 // Special register access 915 void crxor(int bt, int ba, int bb); crclr(int bt)916 void crclr(int bt) { crxor(bt, bt, bt); } 917 void creqv(int bt, int ba, int bb); crset(int bt)918 void crset(int bt) { creqv(bt, bt, bt); } 919 void mflr(Register dst); 920 void mtlr(Register src); 921 void mtctr(Register src); 922 void mtxer(Register src); 923 void mcrfs(CRegister cr, FPSCRBit bit); 924 void mfcr(Register dst); 925 #if V8_TARGET_ARCH_PPC64 926 void mffprd(Register dst, DoubleRegister src); 927 void mffprwz(Register dst, DoubleRegister src); 928 void mtfprd(DoubleRegister dst, Register src); 929 void mtfprwz(DoubleRegister dst, Register src); 930 void mtfprwa(DoubleRegister dst, Register src); 931 #endif 932 933 // Exception-generating instructions and debugging support 934 void stop(Condition cond = al, int32_t code = kDefaultStopCode, 935 CRegister cr = cr7); 936 937 void bkpt(uint32_t imm16); // v5 and above 938 939 void dcbf(Register ra, Register rb); 940 void sync(); 941 void lwsync(); 942 void icbi(Register ra, Register rb); 943 void isync(); 944 945 // Support for floating point 946 void lfd(const DoubleRegister frt, const MemOperand& src); 947 void lfdu(const DoubleRegister frt, const MemOperand& src); 948 void lfs(const DoubleRegister frt, const MemOperand& src); 949 void lfsu(const DoubleRegister frt, const MemOperand& src); 950 void stfd(const DoubleRegister frs, const MemOperand& src); 951 void stfdu(const DoubleRegister frs, const MemOperand& src); 952 void stfs(const DoubleRegister frs, const MemOperand& src); 953 void stfsu(const DoubleRegister frs, const MemOperand& src); 954 955 void fadd(const DoubleRegister frt, const DoubleRegister fra, 956 const DoubleRegister frb, RCBit rc = LeaveRC); 957 void fsub(const DoubleRegister frt, const DoubleRegister fra, 958 const DoubleRegister frb, RCBit rc = LeaveRC); 959 void fdiv(const DoubleRegister frt, const DoubleRegister fra, 960 const DoubleRegister frb, RCBit rc = LeaveRC); 961 void fmul(const DoubleRegister frt, const DoubleRegister fra, 962 const DoubleRegister frc, RCBit rc = LeaveRC); 963 void fcmpu(const DoubleRegister fra, const DoubleRegister frb, 964 CRegister cr = cr7); 965 void fmr(const DoubleRegister frt, const DoubleRegister frb, 966 RCBit rc = LeaveRC); 967 void fctiwz(const DoubleRegister frt, const DoubleRegister frb); 968 void fctiw(const DoubleRegister frt, const DoubleRegister frb); 969 void fctiwuz(const DoubleRegister frt, const DoubleRegister frb); 970 void frin(const DoubleRegister frt, const DoubleRegister frb, 971 RCBit rc = LeaveRC); 972 void friz(const DoubleRegister frt, const DoubleRegister frb, 973 RCBit rc = LeaveRC); 974 void frip(const DoubleRegister frt, const DoubleRegister frb, 975 RCBit rc = LeaveRC); 976 void frim(const DoubleRegister frt, const DoubleRegister frb, 977 RCBit rc = LeaveRC); 978 void frsp(const DoubleRegister frt, const DoubleRegister frb, 979 RCBit rc = LeaveRC); 980 void fcfid(const DoubleRegister frt, const DoubleRegister frb, 981 RCBit rc = LeaveRC); 982 void fcfidu(const DoubleRegister frt, const DoubleRegister frb, 983 RCBit rc = LeaveRC); 984 void fcfidus(const DoubleRegister frt, const DoubleRegister frb, 985 RCBit rc = LeaveRC); 986 void fcfids(const DoubleRegister frt, const DoubleRegister frb, 987 RCBit rc = LeaveRC); 988 void fctid(const DoubleRegister frt, const DoubleRegister frb, 989 RCBit rc = LeaveRC); 990 void fctidz(const DoubleRegister frt, const DoubleRegister frb, 991 RCBit rc = LeaveRC); 992 void fctidu(const DoubleRegister frt, const DoubleRegister frb, 993 RCBit rc = LeaveRC); 994 void fctiduz(const DoubleRegister frt, const DoubleRegister frb, 995 RCBit rc = LeaveRC); 996 void fsel(const DoubleRegister frt, const DoubleRegister fra, 997 const DoubleRegister frc, const DoubleRegister frb, 998 RCBit rc = LeaveRC); 999 void fneg(const DoubleRegister frt, const DoubleRegister frb, 1000 RCBit rc = LeaveRC); 1001 void mtfsb0(FPSCRBit bit, RCBit rc = LeaveRC); 1002 void mtfsb1(FPSCRBit bit, RCBit rc = LeaveRC); 1003 void mtfsfi(int bf, int immediate, RCBit rc = LeaveRC); 1004 void mffs(const DoubleRegister frt, RCBit rc = LeaveRC); 1005 void mtfsf(const DoubleRegister frb, bool L = 1, int FLM = 0, bool W = 0, 1006 RCBit rc = LeaveRC); 1007 void fsqrt(const DoubleRegister frt, const DoubleRegister frb, 1008 RCBit rc = LeaveRC); 1009 void fabs(const DoubleRegister frt, const DoubleRegister frb, 1010 RCBit rc = LeaveRC); 1011 void fmadd(const DoubleRegister frt, const DoubleRegister fra, 1012 const DoubleRegister frc, const DoubleRegister frb, 1013 RCBit rc = LeaveRC); 1014 void fmsub(const DoubleRegister frt, const DoubleRegister fra, 1015 const DoubleRegister frc, const DoubleRegister frb, 1016 RCBit rc = LeaveRC); 1017 1018 // Vector instructions 1019 void mfvsrd(const Register ra, const Simd128Register r); 1020 void mfvsrwz(const Register ra, const Simd128Register r); 1021 void mtvsrd(const Simd128Register rt, const Register ra); 1022 void mtvsrdd(const Simd128Register rt, const Register ra, const Register rb); 1023 void lxvd(const Simd128Register rt, const MemOperand& src); 1024 void stxvd(const Simd128Register rt, const MemOperand& src); 1025 void xxspltib(const Simd128Register rt, const Operand& imm); 1026 1027 // Pseudo instructions 1028 1029 // Different nop operations are used by the code generator to detect certain 1030 // states of the generated code. 1031 enum NopMarkerTypes { 1032 NON_MARKING_NOP = 0, 1033 GROUP_ENDING_NOP, 1034 DEBUG_BREAK_NOP, 1035 // IC markers. 1036 PROPERTY_ACCESS_INLINED, 1037 PROPERTY_ACCESS_INLINED_CONTEXT, 1038 PROPERTY_ACCESS_INLINED_CONTEXT_DONT_DELETE, 1039 // Helper values. 1040 LAST_CODE_MARKER, 1041 FIRST_IC_MARKER = PROPERTY_ACCESS_INLINED 1042 }; 1043 1044 void nop(int type = 0); // 0 is the default non-marking type. 1045 push(Register src)1046 void push(Register src) { 1047 #if V8_TARGET_ARCH_PPC64 1048 stdu(src, MemOperand(sp, -kSystemPointerSize)); 1049 #else 1050 stwu(src, MemOperand(sp, -kSystemPointerSize)); 1051 #endif 1052 } 1053 pop(Register dst)1054 void pop(Register dst) { 1055 #if V8_TARGET_ARCH_PPC64 1056 ld(dst, MemOperand(sp)); 1057 #else 1058 lwz(dst, MemOperand(sp)); 1059 #endif 1060 addi(sp, sp, Operand(kSystemPointerSize)); 1061 } 1062 pop()1063 void pop() { addi(sp, sp, Operand(kSystemPointerSize)); } 1064 1065 // Jump unconditionally to given label. jmp(Label * L)1066 void jmp(Label* L) { b(L); } 1067 1068 // Check the code size generated from label to here. SizeOfCodeGeneratedSince(Label * label)1069 int SizeOfCodeGeneratedSince(Label* label) { 1070 return pc_offset() - label->pos(); 1071 } 1072 1073 // Check the number of instructions generated from label to here. InstructionsGeneratedSince(Label * label)1074 int InstructionsGeneratedSince(Label* label) { 1075 return SizeOfCodeGeneratedSince(label) / kInstrSize; 1076 } 1077 1078 // Class for scoping postponing the trampoline pool generation. 1079 class BlockTrampolinePoolScope { 1080 public: BlockTrampolinePoolScope(Assembler * assem)1081 explicit BlockTrampolinePoolScope(Assembler* assem) : assem_(assem) { 1082 assem_->StartBlockTrampolinePool(); 1083 } ~BlockTrampolinePoolScope()1084 ~BlockTrampolinePoolScope() { assem_->EndBlockTrampolinePool(); } 1085 1086 private: 1087 Assembler* assem_; 1088 1089 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockTrampolinePoolScope); 1090 }; 1091 1092 // Class for scoping disabling constant pool entry merging 1093 class BlockConstantPoolEntrySharingScope { 1094 public: BlockConstantPoolEntrySharingScope(Assembler * assem)1095 explicit BlockConstantPoolEntrySharingScope(Assembler* assem) 1096 : assem_(assem) { 1097 assem_->StartBlockConstantPoolEntrySharing(); 1098 } ~BlockConstantPoolEntrySharingScope()1099 ~BlockConstantPoolEntrySharingScope() { 1100 assem_->EndBlockConstantPoolEntrySharing(); 1101 } 1102 1103 private: 1104 Assembler* assem_; 1105 1106 DISALLOW_IMPLICIT_CONSTRUCTORS(BlockConstantPoolEntrySharingScope); 1107 }; 1108 1109 // Record a deoptimization reason that can be used by a log or cpu profiler. 1110 // Use --trace-deopt to enable. 1111 void RecordDeoptReason(DeoptimizeReason reason, SourcePosition position, 1112 int id); 1113 1114 // Writes a single byte or word of data in the code stream. Used 1115 // for inline tables, e.g., jump-tables. 1116 void db(uint8_t data); 1117 void dd(uint32_t data); 1118 void dq(uint64_t data); 1119 void dp(uintptr_t data); 1120 1121 // Read/patch instructions instr_at(int pos)1122 Instr instr_at(int pos) { 1123 return *reinterpret_cast<Instr*>(buffer_start_ + pos); 1124 } instr_at_put(int pos,Instr instr)1125 void instr_at_put(int pos, Instr instr) { 1126 *reinterpret_cast<Instr*>(buffer_start_ + pos) = instr; 1127 } instr_at(Address pc)1128 static Instr instr_at(Address pc) { return *reinterpret_cast<Instr*>(pc); } instr_at_put(Address pc,Instr instr)1129 static void instr_at_put(Address pc, Instr instr) { 1130 *reinterpret_cast<Instr*>(pc) = instr; 1131 } 1132 static Condition GetCondition(Instr instr); 1133 1134 static bool IsLis(Instr instr); 1135 static bool IsLi(Instr instr); 1136 static bool IsAddic(Instr instr); 1137 static bool IsOri(Instr instr); 1138 1139 static bool IsBranch(Instr instr); 1140 static Register GetRA(Instr instr); 1141 static Register GetRB(Instr instr); 1142 #if V8_TARGET_ARCH_PPC64 1143 static bool Is64BitLoadIntoR12(Instr instr1, Instr instr2, Instr instr3, 1144 Instr instr4, Instr instr5); 1145 #else 1146 static bool Is32BitLoadIntoR12(Instr instr1, Instr instr2); 1147 #endif 1148 1149 static bool IsCmpRegister(Instr instr); 1150 static bool IsCmpImmediate(Instr instr); 1151 static bool IsRlwinm(Instr instr); 1152 static bool IsAndi(Instr instr); 1153 #if V8_TARGET_ARCH_PPC64 1154 static bool IsRldicl(Instr instr); 1155 #endif 1156 static bool IsCrSet(Instr instr); 1157 static Register GetCmpImmediateRegister(Instr instr); 1158 static int GetCmpImmediateRawImmediate(Instr instr); 1159 static bool IsNop(Instr instr, int type = NON_MARKING_NOP); 1160 1161 // Postpone the generation of the trampoline pool for the specified number of 1162 // instructions. 1163 void BlockTrampolinePoolFor(int instructions); 1164 void CheckTrampolinePool(); 1165 1166 // For mov. Return the number of actual instructions required to 1167 // load the operand into a register. This can be anywhere from 1168 // one (constant pool small section) to five instructions (full 1169 // 64-bit sequence). 1170 // 1171 // The value returned is only valid as long as no entries are added to the 1172 // constant pool between this call and the actual instruction being emitted. 1173 int instructions_required_for_mov(Register dst, const Operand& src) const; 1174 1175 // Decide between using the constant pool vs. a mov immediate sequence. 1176 bool use_constant_pool_for_mov(Register dst, const Operand& src, 1177 bool canOptimize) const; 1178 1179 // The code currently calls CheckBuffer() too often. This has the side 1180 // effect of randomly growing the buffer in the middle of multi-instruction 1181 // sequences. 1182 // 1183 // This function allows outside callers to check and grow the buffer 1184 void EnsureSpaceFor(int space_needed); 1185 EmitConstantPool()1186 int EmitConstantPool() { return constant_pool_builder_.Emit(this); } 1187 ConstantPoolAccessIsInOverflow()1188 bool ConstantPoolAccessIsInOverflow() const { 1189 return constant_pool_builder_.NextAccess(ConstantPoolEntry::INTPTR) == 1190 ConstantPoolEntry::OVERFLOWED; 1191 } 1192 ConstantPoolPosition()1193 Label* ConstantPoolPosition() { 1194 return constant_pool_builder_.EmittedPosition(); 1195 } 1196 1197 void EmitRelocations(); 1198 1199 protected: buffer_space()1200 int buffer_space() const { return reloc_info_writer.pos() - pc_; } 1201 1202 // Decode instruction(s) at pos and return backchain to previous 1203 // label reference or kEndOfChain. 1204 int target_at(int pos); 1205 1206 // Patch instruction(s) at pos to target target_pos (e.g. branch) 1207 void target_at_put(int pos, int target_pos, bool* is_branch = nullptr); 1208 1209 // Record reloc info for current pc_ 1210 void RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data = 0); ConstantPoolAddEntry(RelocInfo::Mode rmode,intptr_t value)1211 ConstantPoolEntry::Access ConstantPoolAddEntry(RelocInfo::Mode rmode, 1212 intptr_t value) { 1213 bool sharing_ok = 1214 RelocInfo::IsNone(rmode) || 1215 (!options().record_reloc_info_for_serialization && 1216 RelocInfo::IsShareableRelocMode(rmode) && 1217 !is_constant_pool_entry_sharing_blocked() && 1218 // TODO(johnyan): make the following rmode shareable 1219 !RelocInfo::IsWasmCall(rmode) && !RelocInfo::IsWasmStubCall(rmode)); 1220 return constant_pool_builder_.AddEntry(pc_offset(), value, sharing_ok); 1221 } ConstantPoolAddEntry(Double value)1222 ConstantPoolEntry::Access ConstantPoolAddEntry(Double value) { 1223 return constant_pool_builder_.AddEntry(pc_offset(), value); 1224 } 1225 1226 // Block the emission of the trampoline pool before pc_offset. BlockTrampolinePoolBefore(int pc_offset)1227 void BlockTrampolinePoolBefore(int pc_offset) { 1228 if (no_trampoline_pool_before_ < pc_offset) 1229 no_trampoline_pool_before_ = pc_offset; 1230 } 1231 StartBlockTrampolinePool()1232 void StartBlockTrampolinePool() { trampoline_pool_blocked_nesting_++; } EndBlockTrampolinePool()1233 void EndBlockTrampolinePool() { 1234 int count = --trampoline_pool_blocked_nesting_; 1235 if (count == 0) CheckTrampolinePoolQuick(); 1236 } is_trampoline_pool_blocked()1237 bool is_trampoline_pool_blocked() const { 1238 return trampoline_pool_blocked_nesting_ > 0; 1239 } 1240 StartBlockConstantPoolEntrySharing()1241 void StartBlockConstantPoolEntrySharing() { 1242 constant_pool_entry_sharing_blocked_nesting_++; 1243 } EndBlockConstantPoolEntrySharing()1244 void EndBlockConstantPoolEntrySharing() { 1245 constant_pool_entry_sharing_blocked_nesting_--; 1246 } is_constant_pool_entry_sharing_blocked()1247 bool is_constant_pool_entry_sharing_blocked() const { 1248 return constant_pool_entry_sharing_blocked_nesting_ > 0; 1249 } 1250 has_exception()1251 bool has_exception() const { return internal_trampoline_exception_; } 1252 is_trampoline_emitted()1253 bool is_trampoline_emitted() const { return trampoline_emitted_; } 1254 1255 // Code generation 1256 // The relocation writer's position is at least kGap bytes below the end of 1257 // the generated instructions. This is so that multi-instruction sequences do 1258 // not have to check for overflow. The same is true for writes of large 1259 // relocation info entries. 1260 static constexpr int kGap = 32; 1261 STATIC_ASSERT(AssemblerBase::kMinimalBufferSize >= 2 * kGap); 1262 1263 RelocInfoWriter reloc_info_writer; 1264 1265 private: 1266 // Avoid overflows for displacements etc. 1267 static const int kMaximalBufferSize = 512 * MB; 1268 1269 // Repeated checking whether the trampoline pool should be emitted is rather 1270 // expensive. By default we only check again once a number of instructions 1271 // has been generated. 1272 int next_trampoline_check_; // pc offset of next buffer check. 1273 1274 // Emission of the trampoline pool may be blocked in some code sequences. 1275 int trampoline_pool_blocked_nesting_; // Block emission if this is not zero. 1276 int no_trampoline_pool_before_; // Block emission before this pc offset. 1277 1278 // Do not share constant pool entries. 1279 int constant_pool_entry_sharing_blocked_nesting_; 1280 1281 // Relocation info generation 1282 // Each relocation is encoded as a variable size value 1283 static constexpr int kMaxRelocSize = RelocInfoWriter::kMaxSize; 1284 std::vector<DeferredRelocInfo> relocations_; 1285 1286 // Scratch registers available for use by the Assembler. 1287 RegList scratch_register_list_; 1288 1289 // The bound position, before this we cannot do instruction elimination. 1290 int last_bound_pos_; 1291 // Optimizable cmpi information. 1292 int optimizable_cmpi_pos_; 1293 CRegister cmpi_cr_ = CRegister::no_reg(); 1294 1295 ConstantPoolBuilder constant_pool_builder_; 1296 CheckBuffer()1297 void CheckBuffer() { 1298 if (buffer_space() <= kGap) { 1299 GrowBuffer(); 1300 } 1301 } 1302 1303 void GrowBuffer(int needed = 0); 1304 // Code emission emit(Instr x)1305 void emit(Instr x) { 1306 CheckBuffer(); 1307 *reinterpret_cast<Instr*>(pc_) = x; 1308 pc_ += kInstrSize; 1309 CheckTrampolinePoolQuick(); 1310 } TrackBranch()1311 void TrackBranch() { 1312 DCHECK(!trampoline_emitted_); 1313 int count = tracked_branch_count_++; 1314 if (count == 0) { 1315 // We leave space (kMaxBlockTrampolineSectionSize) 1316 // for BlockTrampolinePoolScope buffer. 1317 next_trampoline_check_ = 1318 pc_offset() + kMaxCondBranchReach - kMaxBlockTrampolineSectionSize; 1319 } else { 1320 next_trampoline_check_ -= kTrampolineSlotsSize; 1321 } 1322 } 1323 1324 inline void UntrackBranch(); CheckTrampolinePoolQuick()1325 void CheckTrampolinePoolQuick() { 1326 if (pc_offset() >= next_trampoline_check_) { 1327 CheckTrampolinePool(); 1328 } 1329 } 1330 1331 // Instruction generation 1332 void a_form(Instr instr, DoubleRegister frt, DoubleRegister fra, 1333 DoubleRegister frb, RCBit r); 1334 void d_form(Instr instr, Register rt, Register ra, const intptr_t val, 1335 bool signed_disp); 1336 void xo_form(Instr instr, Register rt, Register ra, Register rb, OEBit o, 1337 RCBit r); 1338 void md_form(Instr instr, Register ra, Register rs, int shift, int maskbit, 1339 RCBit r); 1340 void mds_form(Instr instr, Register ra, Register rs, Register rb, int maskbit, 1341 RCBit r); 1342 1343 // Labels 1344 void print(Label* L); 1345 int max_reach_from(int pos); 1346 void bind_to(Label* L, int pos); 1347 void next(Label* L); 1348 1349 class Trampoline { 1350 public: Trampoline()1351 Trampoline() { 1352 next_slot_ = 0; 1353 free_slot_count_ = 0; 1354 } Trampoline(int start,int slot_count)1355 Trampoline(int start, int slot_count) { 1356 next_slot_ = start; 1357 free_slot_count_ = slot_count; 1358 } take_slot()1359 int take_slot() { 1360 int trampoline_slot = kInvalidSlotPos; 1361 if (free_slot_count_ <= 0) { 1362 // We have run out of space on trampolines. 1363 // Make sure we fail in debug mode, so we become aware of each case 1364 // when this happens. 1365 DCHECK(0); 1366 // Internal exception will be caught. 1367 } else { 1368 trampoline_slot = next_slot_; 1369 free_slot_count_--; 1370 next_slot_ += kTrampolineSlotsSize; 1371 } 1372 return trampoline_slot; 1373 } 1374 1375 private: 1376 int next_slot_; 1377 int free_slot_count_; 1378 }; 1379 1380 int32_t get_trampoline_entry(); 1381 int tracked_branch_count_; 1382 // If trampoline is emitted, generated code is becoming large. As 1383 // this is already a slow case which can possibly break our code 1384 // generation for the extreme case, we use this information to 1385 // trigger different mode of branch instruction generation, where we 1386 // no longer use a single branch instruction. 1387 bool trampoline_emitted_; 1388 static constexpr int kTrampolineSlotsSize = kInstrSize; 1389 static constexpr int kMaxCondBranchReach = (1 << (16 - 1)) - 1; 1390 static constexpr int kMaxBlockTrampolineSectionSize = 64 * kInstrSize; 1391 static constexpr int kInvalidSlotPos = -1; 1392 1393 Trampoline trampoline_; 1394 bool internal_trampoline_exception_; 1395 1396 void AllocateAndInstallRequestedHeapObjects(Isolate* isolate); 1397 1398 int WriteCodeComments(); 1399 1400 friend class RegExpMacroAssemblerPPC; 1401 friend class RelocInfo; 1402 friend class BlockTrampolinePoolScope; 1403 friend class EnsureSpace; 1404 friend class UseScratchRegisterScope; 1405 }; 1406 1407 class EnsureSpace { 1408 public: EnsureSpace(Assembler * assembler)1409 explicit EnsureSpace(Assembler* assembler) { assembler->CheckBuffer(); } 1410 }; 1411 1412 class PatchingAssembler : public Assembler { 1413 public: 1414 PatchingAssembler(const AssemblerOptions& options, byte* address, 1415 int instructions); 1416 ~PatchingAssembler(); 1417 }; 1418 1419 class V8_EXPORT_PRIVATE UseScratchRegisterScope { 1420 public: 1421 explicit UseScratchRegisterScope(Assembler* assembler); 1422 ~UseScratchRegisterScope(); 1423 1424 Register Acquire(); 1425 1426 // Check if we have registers available to acquire. CanAcquire()1427 bool CanAcquire() const { return *assembler_->GetScratchRegisterList() != 0; } 1428 1429 private: 1430 friend class Assembler; 1431 friend class TurboAssembler; 1432 1433 Assembler* assembler_; 1434 RegList old_available_; 1435 }; 1436 1437 } // namespace internal 1438 } // namespace v8 1439 1440 #endif // V8_CODEGEN_PPC_ASSEMBLER_PPC_H_ 1441