2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | (c) Copyright IBM Corporation 2015-2016 |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
17 #ifndef incl_HPHP_PPC64_ASM_ASM_PPC64_H_
18 #define incl_HPHP_PPC64_ASM_ASM_PPC64_H_
24 #include "hphp/util/data-block.h"
26 #include "hphp/ppc64-asm/branch-ppc64.h"
27 #include "hphp/ppc64-asm/decoded-instr-ppc64.h"
28 #include "hphp/ppc64-asm/isa-ppc64.h"
33 /* using override */ using HPHP::jit::Reg64
;
34 /* using override */ using HPHP::jit::RegXMM
;
35 /* using override */ using HPHP::jit::RegSF
;
36 /* using override */ using HPHP::jit::MemoryRef
;
37 /* using override */ using HPHP::jit::Immed
;
38 /* using override */ using HPHP::CodeAddress
;
39 /* using override */ using HPHP::jit::ConditionCode
;
41 //////////////////////////////////////////////////////////////////////
44 * Constants definition for PPC64
47 // Must be the same value of AROFF(m_func).
48 constexpr uint8_t min_frame_size
= 4 * 8;
49 // Must be the same value of AROFF(m_savedToc).
50 constexpr uint8_t toc_position_on_frame
= 3 * 8;
52 // Amount of bytes to skip after an Assembler::call to grab the return address.
53 // Currently it skips a "nop" or a "ld 2,24(1)"
54 constexpr uint8_t call_skip_bytes_for_ret
= 1 * instr_size_in_bytes
;
56 //////////////////////////////////////////////////////////////////////
58 enum class RegNumber
: uint32_t {};
61 constexpr Reg64
r0(0); // volatile, used in function prologue / linkage
62 constexpr Reg64
r1(1); // nonvolatile, stack pointer
63 constexpr Reg64
r2(2); // nonvolatile, TOC
64 /* volatile, argument passing registers */
65 constexpr Reg64
r3(3);
66 constexpr Reg64
r4(4);
67 constexpr Reg64
r5(5);
68 constexpr Reg64
r6(6);
69 constexpr Reg64
r7(7);
70 constexpr Reg64
r8(8);
71 constexpr Reg64
r9(9);
72 constexpr Reg64
r10(10);
74 constexpr Reg64
r11(11); // volatile, environment pointer (scratch)
75 constexpr Reg64
r12(12); // volatile, function entry address
76 constexpr Reg64
r13(13); // reserved, thread pointer
77 /* nonvolatile, local variables */
78 constexpr Reg64
r14(14);
79 constexpr Reg64
r15(15);
80 constexpr Reg64
r16(16);
81 constexpr Reg64
r17(17);
82 constexpr Reg64
r18(18);
83 constexpr Reg64
r19(19);
84 constexpr Reg64
r20(20);
85 constexpr Reg64
r21(21);
86 constexpr Reg64
r22(22);
87 constexpr Reg64
r23(23);
88 constexpr Reg64
r24(24);
89 constexpr Reg64
r25(25);
90 constexpr Reg64
r26(26);
91 constexpr Reg64
r27(27);
92 constexpr Reg64
r28(28);
93 constexpr Reg64
r29(29);
94 constexpr Reg64
r30(30);
95 constexpr Reg64
r31(31);
97 // RegXMM is used for both FP and SIMD registers. Registers from 0 to 15 are
98 // reserved to FP and register from 16 to 29 are reserved to SIMD.
99 // Ignoring the vector registers 30, 31 due to kMaxRegs == 64
100 constexpr RegXMM
f0(0); // volatile scratch register
101 /* volatile, argument passing floating point registers */
102 constexpr RegXMM
f1(1);
103 constexpr RegXMM
f2(2);
104 constexpr RegXMM
f3(3);
105 constexpr RegXMM
f4(4);
106 constexpr RegXMM
f5(5);
107 constexpr RegXMM
f6(6);
108 constexpr RegXMM
f7(7);
109 constexpr RegXMM
f8(8);
110 constexpr RegXMM
f9(9);
111 constexpr RegXMM
f10(10);
112 constexpr RegXMM
f11(11);
113 constexpr RegXMM
f12(12);
114 constexpr RegXMM
f13(13);
115 /* nonvolatile, local variables */
116 constexpr RegXMM
f14(14);
117 constexpr RegXMM
f15(15);
119 /* volatile, local variables */
120 constexpr RegXMM
v16(16);
121 constexpr RegXMM
v17(17);
122 constexpr RegXMM
v18(18);
123 constexpr RegXMM
v19(19);
124 /* nonvolatile, local variables */
125 constexpr RegXMM
v20(20);
126 constexpr RegXMM
v21(21);
127 constexpr RegXMM
v22(22);
128 constexpr RegXMM
v23(23);
129 constexpr RegXMM
v24(24);
130 constexpr RegXMM
v25(25);
131 constexpr RegXMM
v26(26);
132 constexpr RegXMM
v27(27);
133 constexpr RegXMM
v28(28);
134 constexpr RegXMM
v29(29);
135 constexpr RegXMM
v30(30);
136 constexpr RegXMM
v31(31);
138 #define RNAME(x) if (r == x) return #x
140 inline const char* regname(Reg64 r
) {
141 RNAME(r0
); RNAME(r1
); RNAME(r2
); RNAME(r3
); RNAME(r4
); RNAME(r5
);
142 RNAME(r6
); RNAME(r7
); RNAME(r8
); RNAME(r9
); RNAME(r10
); RNAME(r11
);
143 RNAME(r12
); RNAME(r13
); RNAME(r14
); RNAME(r15
); RNAME(r16
); RNAME(r17
);
144 RNAME(r18
); RNAME(r19
); RNAME(r20
); RNAME(r21
); RNAME(r22
); RNAME(r23
);
145 RNAME(r24
); RNAME(r25
); RNAME(r26
); RNAME(r27
); RNAME(r28
); RNAME(r29
);
146 RNAME(r30
); RNAME(r31
);
150 inline const char* regname(RegXMM r
) {
151 RNAME(f0
); RNAME(f1
); RNAME(f2
); RNAME(f3
); RNAME(f4
); RNAME(f5
);
152 RNAME(f6
); RNAME(f7
); RNAME(f8
); RNAME(f9
); RNAME(f10
); RNAME(f11
);
153 RNAME(f12
); RNAME(f13
); RNAME(f14
); RNAME(f15
);
155 RNAME(v16
); RNAME(v17
); RNAME(v18
); RNAME(v19
); RNAME(v20
); RNAME(v21
);
156 RNAME(v22
); RNAME(v23
); RNAME(v24
); RNAME(v25
); RNAME(v26
); RNAME(v27
);
157 RNAME(v28
); RNAME(v29
);
160 inline const char* regname(RegSF
) {
166 //////////////////////////////////////////////////////////////////////
168 // Forward declaration to be used in Label
172 // Supports TOC? | Supports li64? | Fixed size?
173 // -------------------------------------------
174 AnyCompact
, // Yes | Yes | No
175 AnyFixed
, // Yes | Yes | Yes (5 instr)
176 TocOnly
, // Yes | No | Yes (2 instr)
185 Label() : m_a(nullptr) , m_address(nullptr) {}
186 /* implicit */ Label(CodeAddress predefined
) : m_a(nullptr) ,
187 m_address(predefined
) {}
191 Label(const Label
&) = delete;
192 Label
& operator=(const Label
&) = delete;
194 void branch(Assembler
& a
, BranchConditions bc
,
195 LinkReg lr
, bool addrMayChange
= false);
196 void branchFar(Assembler
& a
,
199 ImmType immt
= ImmType::TocOnly
,
200 bool immMayChange
= false);
201 void asm_label(Assembler
& a
);
209 void addJump(Assembler
* a
);
212 CodeAddress m_address
;
213 std::vector
<JumpInfo
> m_toPatch
;
217 * Class that represents a virtual TOC
222 // VMTOC is a singleton
224 : m_tocvector(nullptr)
232 VMTOC(VMTOC
const&) = delete;
234 VMTOC
operator=(VMTOC
const&) = delete;
236 void setTOCDataBlock(HPHP::DataBlock
*db
);
239 * Push a 64 bit element into the stack and return its index.
241 int64_t pushElem(int64_t elem
, bool elemMayChange
= false);
244 * Get the singleton instance.
246 static VMTOC
& getInstance();
249 * Return the address of the middle element from the vector.
251 * This is done so signed offsets can be used.
253 intptr_t getPtrVector();
256 * Return a value previously pushed.
258 int64_t getValue(int64_t index
, bool qword
= true);
261 * Return the memory address of the index.
263 uint64_t* getAddr(int64_t index
);
266 * Return TOC index of the element.
268 int64_t getIndex(uint64_t elem
);
271 int64_t allocTOC (int64_t target
);
272 void forceAlignment(HPHP::Address
& addr
);
274 HPHP::DataBlock
*m_tocvector
;
277 * Vector position of the last element.
279 uint64_t m_last_elem_pos
;
282 * Map used to avoid insertion of duplicates.
284 std::map
<int64_t, uint64_t> m_map
;
291 explicit Assembler(HPHP::CodeBlock
& cb
) : codeBlock(cb
) {}
294 HPHP::CodeBlock
& code() const { return codeBlock
; }
296 CodeAddress
base() const {
297 return codeBlock
.base();
300 CodeAddress
frontier() const {
301 return codeBlock
.frontier();
304 void setFrontier(CodeAddress newFrontier
) {
305 codeBlock
.setFrontier(newFrontier
);
308 size_t capacity() const {
309 return codeBlock
.capacity();
312 size_t used() const {
313 return codeBlock
.used();
316 size_t available() const {
317 return codeBlock
.available();
320 bool contains(CodeAddress addr
) const {
321 return codeBlock
.contains(addr
);
324 CodeAddress
toDestAddress(CodeAddress addr
) const {
325 return codeBlock
.toDestAddress(addr
);
329 return codeBlock
.empty();
336 bool canEmit(size_t nBytes
) const {
337 assert(capacity() >= used());
338 return nBytes
< (capacity() - used());
341 enum class SpecialReg
{
385 // Total amount of bytes that a li64 function emits as fixed size
386 static const uint8_t kLi64Len
= instr_size_in_bytes
* 5;
387 // TOC emit length: (ld/lwz + nop) or (addis + ld/lwz)
388 static const uint8_t kTocLen
= instr_size_in_bytes
* 2;
390 // Define using TOC on branches
391 static const uint8_t kLimmLen
= kTocLen
;
393 // Jcc using TOC length: toc/li64 + mtctr + nop + nop + bcctr
394 static const uint8_t kJccLen
= kLimmLen
+ instr_size_in_bytes
* 4;
396 // Call using TOC length: toc/li64 + mtctr + bctr
397 static const uint8_t kCallLen
= kLimmLen
+ instr_size_in_bytes
* 2;
399 // PPC64 Instructions
400 void add(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
401 void addi(const Reg64
& rt
, const Reg64
& ra
, Immed imm
);
402 void addis(const Reg64
& rt
, const Reg64
& ra
, Immed imm
);
403 void addo(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
404 void and(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
405 void andi(const Reg64
& ra
, const Reg64
& rs
, Immed imm
);
406 void b(int32_t offset
);
407 void bl(int32_t offset
);
408 void bc(uint8_t bo
, uint8_t bi
, int16_t offset
);
409 void bcctr(uint8_t bo
, uint8_t bi
, uint16_t bh
);
412 void bctar(uint8_t bo
, uint8_t bi
, uint16_t bh
);
413 void bctarl(uint8_t bo
, uint8_t bi
, uint16_t bh
);
414 void cmp(uint16_t bf
, bool l
, const Reg64
& ra
, const Reg64
& rb
);
415 void cmpi(uint16_t bf
, bool l
, const Reg64
& ra
, Immed imm
);
416 void cmpb(const Reg64
& rs
, const Reg64
& ra
, const Reg64
& rb
);
417 void cmpl(uint16_t bf
, bool l
, const Reg64
& ra
, const Reg64
& rb
);
418 void cmpli(uint16_t bf
, bool l
, const Reg64
& ra
, Immed imm
);
419 void divd(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
420 void extsb(const Reg64
& ra
, const Reg64
& rs
, bool rc
= 0);
421 void extsh(const Reg64
& ra
, const Reg64
& rs
, bool rc
= 0);
422 void extsw(const Reg64
& ra
, const Reg64
& rs
, bool rc
= 0);
423 void fadd(const RegXMM
& frt
, const RegXMM
& fra
, const RegXMM
& frb
,
425 void fsub(const RegXMM
& frt
, const RegXMM
& fra
, const RegXMM
& frb
,
427 void fmul(const RegXMM
& frt
, const RegXMM
& fra
, const RegXMM
& frc
,
429 void fdiv(const RegXMM
& frt
, const RegXMM
& fra
, const RegXMM
& frb
,
431 void lfs(const RegXMM
& frt
, MemoryRef m
) {
432 assertx(Reg64(-1) == m
.r
.index
); // doesn't support base+index
433 EmitDForm(48, rn(frt
), rn(m
.r
.base
), m
.r
.disp
);
435 void lxvd2x(const RegXMM
& Xt
, const MemoryRef
& m
) {
436 assertx(!m
.r
.disp
); // doesn't support immediate displacement
437 EmitXX1Form(31, rn(Xt
), rn(m
.r
.base
), rn(m
.r
.index
), 844, 0);
439 void lxvw4x(const RegXMM
& Xt
, const MemoryRef
& m
) {
440 assertx(!m
.r
.disp
); // doesn't support immediate displacement
441 EmitXX1Form(31, rn(Xt
), rn(m
.r
.base
), rn(m
.r
.index
), 780, 0);
443 void isel(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, uint8_t bc
);
444 void lbz(const Reg64
& rt
, MemoryRef m
);
445 void lbzx(const Reg64
& rt
, MemoryRef m
);
446 void ld(const Reg64
& rt
, MemoryRef m
);
447 void ldx(const Reg64
& rt
, MemoryRef m
);
448 void lhz(const Reg64
& rt
, MemoryRef m
);
449 void lhzx(const Reg64
& rt
, MemoryRef m
);
450 void lwz(const Reg64
& rt
, MemoryRef m
);
451 void lwzx(const Reg64
& rt
, MemoryRef m
);
452 void mfspr(const SpecialReg spr
, const Reg64
& rs
);
453 void mtspr(const SpecialReg spr
, const Reg64
& rs
);
454 void mulldo(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
455 void neg(const Reg64
& rt
, const Reg64
& ra
, bool rc
= 0);
456 void nor(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
457 void or(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
458 void ori(const Reg64
& ra
, const Reg64
& rs
, Immed imm
);
459 void oris(const Reg64
& ra
, const Reg64
& rs
, Immed imm
);
460 void rldicl(const Reg64
& ra
, const Reg64
& rs
, uint8_t sh
,
461 uint8_t mb
, bool rc
= 0);
462 void rldicr(const Reg64
& ra
, const Reg64
& rs
, uint8_t sh
,
463 uint8_t mb
, bool rc
= 0);
464 void rlwinm(const Reg64
& ra
, const Reg64
& rs
, uint8_t sh
, uint8_t mb
,
465 uint16_t me
, bool rc
= 0);
466 void sld(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
467 void srad(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
468 void stb(const Reg64
& rs
, MemoryRef m
);
469 void stbx(const Reg64
& rs
, MemoryRef m
);
470 void stfs(const RegXMM
& frt
, MemoryRef m
) {
471 EmitDForm(52, rn(frt
), rn(m
.r
.base
), m
.r
.disp
);
473 void sth(const Reg64
& rs
, MemoryRef m
);
474 void sthx(const Reg64
& rs
, MemoryRef m
);
475 void stw(const Reg64
& rs
, MemoryRef m
);
476 void stwx(const Reg64
& rs
, MemoryRef m
);
477 void std(const Reg64
& rs
, MemoryRef m
);
478 void stdu(const Reg64
& rs
, MemoryRef m
);
479 void stdx(const Reg64
& rs
, MemoryRef m
);
480 void stxvw4x(const RegXMM
& xs
, const MemoryRef
& m
) {
481 EmitXX1Form(31, rn(xs
), rn(m
.r
.base
), rn(m
.r
.index
), 972, 0);
483 void subf(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
484 void subfo(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0);
485 void td(uint16_t to
, const Reg64
& ra
, const Reg64
& rb
);
486 void tw(uint16_t to
, const Reg64
& ra
, const Reg64
& rb
);
487 void xor(const Reg64
& ra
, const Reg64
& rs
, const Reg64
& rb
, bool rc
= 0);
488 void xscvdpuxds(const RegXMM
& xt
, const RegXMM
& xb
) {
489 //TODO(rcardoso): bx tx bits
490 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 328, 0, 0);
492 void xvdivdp(const RegXMM
& xt
, const RegXMM
& xa
, const RegXMM
& xb
) {
493 EmitXX3Form(60, rn(xt
), rn(xa
), rn(xb
), 56, 0, 0 ,0);
495 void xvdivsp(const RegXMM
& xt
, const RegXMM
& xa
, const RegXMM
& xb
) {
496 EmitXX3Form(60, rn(xt
), rn(xa
), rn(xb
), 24, 0, 0 ,0);
499 // Unimplemented Instructions
500 void dcmpu(const RegXMM
& fra
, const RegXMM
& frb
) {
501 EmitXForm(59, rn(0), rn(fra
), rn(frb
), 642);
503 void fabs(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
504 EmitXForm(63, rn(frt
), rn(0), rn(frb
), 264, rc
);
506 void fcfid(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
507 EmitXForm(63, rn(frt
), rn(0), rn(frb
), 846, rc
);
510 void fcfids(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
511 EmitXForm(59, rn(frt
), rn(0), rn(frb
), 846, rc
);
513 void fcmpo(const RegSF
& sf
, const RegXMM
& fra
, const RegXMM
& frb
) {
514 EmitXForm(63, rn(int(sf
) << 2), rn(fra
), rn(frb
), 32);
516 void fcmpu(const RegSF
& sf
, const RegXMM
& fra
, const RegXMM
& frb
) {
517 EmitXForm(63, rn(int(sf
) << 2), rn(fra
), rn(frb
), 0);
519 void fctid(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
520 EmitXForm(63, rn(frt
), rn(0), rn(frb
), 814, rc
);
522 void fctidz(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
523 EmitXForm(63, rn(frt
), rn(0), rn(frb
), 815, rc
);
525 void fmr(const RegXMM
& frt
, const RegXMM
& frb
, bool rc
= 0) {
526 EmitXForm(63, rn(frt
), rn(0), rn(frb
), 72, rc
);
528 //TODO(rcardoso); check default for EH bit
529 void ldarx(const Reg64
& rt
, MemoryRef m
, bool eh
= 1) {
530 assertx(!m
.r
.disp
); // doesn't support immediate displacement
531 EmitXForm(31, rn(rt
), rn(m
.r
.base
), rn(m
.r
.index
), 84, eh
);
533 void lfd(const RegXMM
& frt
, MemoryRef m
) {
534 assertx(Reg64(-1) == m
.r
.index
); // doesn't support base+index
535 EmitDForm(50, rn(frt
), rn(m
.r
.base
), m
.r
.disp
);
537 void lfdx(const RegXMM
& rt
, MemoryRef m
) {
538 assertx(!m
.r
.disp
); // doesn't support immediate displacement
539 EmitXForm(31, rn(rt
), rn(m
.r
.base
), rn(m
.r
.index
), 599);
541 void mcrfs(uint8_t bf
, uint8_t bfa
) {
542 EmitXForm(63, (bf
<< 2), (bfa
<< 2), 0, 64);
544 void mfcr(const Reg64
& rt
) {
545 EmitXFXForm(31, rn(rt
), static_cast<SpecialReg
>(0), 19);
547 void mfvsrd(const Reg64
& ra
, const RegXMM
& xs
) {
548 EmitXX1Form(31, rn(xs
), rn(ra
), rn(0) /* reserved */, 51, 0);
550 void mtcrf(uint16_t fxm
, const Reg64
& ra
) {
551 EmitXFXForm(31, rn(ra
), (fxm
<< 1), 144);
553 void mtocrf(uint16_t fxm
, const Reg64
& rt
) {
554 EmitXFXForm(31, rn(rt
), ( ((fxm
<< 1) & 0x1fe) |0x200), 144);
556 void mtfsb0(uint8_t bt
) { EmitXForm(63, bt
, 0 , 0, 70); }
557 void mtvsrd(const RegXMM
& xt
, const Reg64
& ra
) {
558 EmitXX1Form(31, rn(xt
), rn(ra
), rn(0) /* reserved */, 179, 0);
560 void sradi(const Reg64
& ra
, const Reg64
& rs
, uint8_t sh
, bool rc
= 0);
561 void stdcx(const Reg64
& rt
, MemoryRef m
) {
562 assertx(!m
.r
.disp
); // doesn't support immediate displacement
563 EmitXForm(31, rn(rt
), rn(m
.r
.base
), rn(m
.r
.index
), 214, 1);
565 void stfd(const RegXMM
& frt
, MemoryRef m
) {
566 assertx(Reg64(-1) == m
.r
.index
); // doesn't support base+index
567 EmitDForm(54, rn(frt
), rn(m
.r
.base
), m
.r
.disp
);
569 void stfdx(const RegXMM
& rt
, MemoryRef m
) {
570 assertx(!m
.r
.disp
); // doesn't support immediate displacement
571 EmitXForm(31, rn(rt
), rn(m
.r
.base
), rn(m
.r
.index
), 727);
573 void xscvdpsxds(const RegXMM
& xt
, const RegXMM
& xb
) {
574 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 344, 0, 0);
576 void xscvsxddp(const RegXMM
& xt
, const RegXMM
& xb
) {
577 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 376, 0, 0);
579 void xsrdpi(const RegXMM
& xt
, const RegXMM
& xb
) {
580 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 73, 0, 0);
582 void xssqrtdp(const RegXMM
& xt
, const RegXMM
& xb
) {
583 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 75, 0, 0);
585 void xvcvspsxds(const RegXMM
& xt
, const RegXMM
& xb
) {
586 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 408, 0, 0);
588 void xvcvspsxws(const RegXMM
& xt
, const RegXMM
& xb
) {
589 EmitXX2Form(60, rn(xt
), 0, rn(xb
), 152, 0, 0);
591 void xxlxor(const RegXMM
& xt
, const RegXMM
& xa
, const RegXMM
& xb
) {
592 EmitXX3Form(60, rn(xt
), rn(xa
), rn(xb
), 154, 0, 0, 0);
594 void xxpermdi(const RegXMM
& tx
, const RegXMM
& xa
, const RegXMM
& xb
) {
595 EmitXX3Form(60, rn(tx
), rn(xa
), rn(xb
), 10, 0, 0, 0);
596 // Note that I decided to hardcode DM bit as 0
597 // (xo field = 10), because it's sufficent for now.
598 // However, I might not be the case in the future
601 //Extended/Synthetic PPC64 Instructions
603 BranchParams
bp(BranchConditions::Always
);
604 bcctr(bp
.bo(), bp
.bi(), 0);
606 void li(const Reg64
& rt
, Immed imm
) {
607 addi(rt
, Reg64(0), imm
);
609 void subi(const Reg64
& rt
, const Reg64
& ra
, Immed imm
) {
612 void lis(const Reg64
& rt
, Immed imm
) {
613 addis(rt
, Reg64(0), imm
);
615 void sub(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0) {
616 subf(rt
, rb
, ra
, rc
);
618 void subo(const Reg64
& rt
, const Reg64
& ra
, const Reg64
& rb
, bool rc
= 0) {
619 subfo(rt
, rb
, ra
, rc
);
621 void cmpdi(const Reg64
& ra
, Immed imm
) {
624 void cmpwi(const Reg64
& ra
, Immed imm
) {
625 //Extended cmpi 3,0,Rx,value
626 // TODO(CRField): if other CRs than 0 is used, please change this to 3
629 void cmpd(const Reg64
& ra
, const Reg64
& rb
) {
632 void cmpw(const Reg64
& ra
, const Reg64
& rb
) {
633 //Extended cmp 3,0,Rx,Ry
634 // TODO(CRField): if other CRs than 0 is used, please change this to 3
637 void cmpldi(const Reg64
& ra
, Immed imm
, CR CRnum
= CR::CR0
) {
638 cmpli(static_cast<uint16_t>(CRnum
), 1, ra
, imm
);
640 void cmplwi(const Reg64
& ra
, Immed imm
, CR CRnum
= CR::CR0
) {
641 //Extended cmpli 3,0,Rx,value
642 // TODO(CRField): if other CRs than 0 is used, please change this to 3
643 cmpli(static_cast<uint16_t>(CRnum
), 0, ra
, imm
);
645 void cmpld(const Reg64
& ra
, const Reg64
& rb
, CR CRnum
= CR::CR0
) {
646 cmpl(static_cast<uint16_t>(CRnum
), 1, ra
, rb
);
648 void cmplw(const Reg64
& ra
, const Reg64
& rb
, CR CRnum
= CR::CR0
) {
649 //Extended cmpl 3,0,Rx,Ry
650 // TODO(CRField): if other CRs than 0 is used, please change this to 3
651 cmpl(static_cast<uint16_t>(CRnum
), 0, ra
, rb
);
654 tw(31, Reg64(0), Reg64(0));
657 ori(Reg64(0),Reg64(0),0);
659 void mr(const Reg64
& rs
, const Reg64
& ra
) {
662 void srwi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
663 rlwinm(ra
, rs
, 32-sh
, sh
, 31, rc
);
665 void slwi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
666 /* non-existing mnemonic on ISA, but it's pratical to have it here */
667 rlwinm(ra
, rs
, sh
, 0, 31-sh
, rc
);
669 void srdi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
670 rldicl(ra
, rs
, 64-sh
, sh
, rc
);
672 void clrldi(const Reg64
& ra
, const Reg64
& rs
, int8_t mb
, bool rc
= 0) {
673 rldicl(ra
, rs
, 0, mb
, rc
);
675 void sldi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
676 rldicr(ra
, rs
, sh
, 63-sh
, rc
);
678 void clrrdi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
679 rldicr(ra
, rs
, 0, 63-sh
, rc
);
681 void clrrwi(const Reg64
& ra
, const Reg64
& rs
, int8_t sh
, bool rc
= 0) {
682 rlwinm(ra
, rs
, 0, 0, 31-sh
, rc
);
684 void mtctr(const Reg64
& rx
) {
685 mtspr(SpecialReg::CTR
, rx
);
687 void mtlr(const Reg64
& rx
) {
688 mtspr(SpecialReg::LR
, rx
);
690 void mfctr(const Reg64
& rx
) {
691 mfspr(SpecialReg::CTR
, rx
);
693 void mflr(const Reg64
& rx
) {
694 mfspr(SpecialReg::LR
, rx
);
699 // Simplify to conditional branch that always branch
700 void b(Label
& l
) { bc(l
, BranchConditions::Always
); }
702 void bc(Label
& l
, BranchConditions bc
) {
703 l
.branch(*this, bc
, LinkReg::DoNotTouch
);
705 void bc(Label
& l
, ConditionCode cc
) {
706 l
.branch(*this, BranchParams::convertCC(cc
), LinkReg::DoNotTouch
);
709 l
.branch(*this, BranchConditions::Always
, LinkReg::Save
);
712 void branchAuto(Label
& l
,
713 BranchConditions bc
= BranchConditions::Always
,
714 LinkReg lr
= LinkReg::DoNotTouch
,
715 bool addrMayChange
= false) {
716 l
.branch(*this, bc
, lr
, addrMayChange
);
719 void branchAuto(CodeAddress c
,
720 BranchConditions bc
= BranchConditions::Always
,
721 LinkReg lr
= LinkReg::DoNotTouch
,
722 bool addrMayChange
= false) {
724 l
.branch(*this, bc
, lr
, addrMayChange
);
727 void branchAuto(CodeAddress c
,
729 LinkReg lr
= LinkReg::DoNotTouch
) {
730 branchAuto(c
, BranchParams::convertCC(cc
), lr
);
733 void branchFar(Label
& l
,
734 BranchConditions bc
= BranchConditions::Always
,
735 LinkReg lr
= LinkReg::DoNotTouch
,
736 ImmType immt
= ImmType::TocOnly
,
737 bool immMayChange
= false) {
738 l
.branchFar(*this, bc
, lr
, immt
, immMayChange
);
741 void branchFar(CodeAddress c
,
742 BranchConditions bc
= BranchConditions::Always
,
743 LinkReg lr
= LinkReg::DoNotTouch
,
744 ImmType immt
= ImmType::TocOnly
,
745 bool immMayChange
= false) {
747 l
.branchFar(*this, bc
, lr
, immt
, immMayChange
);
750 void branchFar(CodeAddress c
,
752 LinkReg lr
= LinkReg::DoNotTouch
,
753 ImmType immt
= ImmType::TocOnly
,
754 bool immMayChange
= false) {
755 branchFar(c
, BranchParams::convertCC(cc
), lr
, immt
, immMayChange
);
758 void branchFar(CodeAddress c
, BranchParams bp
,
759 ImmType immt
= ImmType::TocOnly
,
760 bool immMayChange
= false) {
761 LinkReg lr
= (bp
.savesLR()) ? LinkReg::Save
: LinkReg::DoNotTouch
;
762 branchFar(c
, static_cast<BranchConditions
>(bp
), lr
, immt
, immMayChange
);
765 // ConditionCode variants
766 void bc(ConditionCode cc
, int16_t address
) {
768 bc(bp
.bo(), bp
.bi(), address
);
771 //////////////////////////////////////////////////////////////////////
774 // Saves TOC? | Smashable?
775 // --------------------------
777 External
, // Yes | No
778 SmashInt
, // No | Yes
779 SmashExt
, // Yes | Yes
782 void callEpilogue(CallArg ca
) {
783 // Several vasms like nothrow, unwind and syncpoint will skip one
784 // instruction after call and use it as expected return address. Use a nop
785 // to guarantee this consistency even if toc doesn't need to be saved
786 if ((CallArg::SmashInt
== ca
) || (CallArg::Internal
== ca
)) nop();
787 else ld(reg::r2
, reg::r1
[toc_position_on_frame
]);
790 // generic template, for CodeAddress and Label
791 template <typename T
>
792 void call(T
& target
, CallArg ca
= CallArg::Internal
) {
793 if (CallArg::Internal
== ca
) {
794 // tries best performance possible
795 branchAuto(target
, BranchConditions::Always
, LinkReg::Save
, true);
797 // branchFar is not only smashable but also it will use r12 so an
798 // external branch can correctly set its TOC address appropriately.
799 branchFar(target
, BranchConditions::Always
, LinkReg::Save
,
800 ImmType::TocOnly
, true);
805 // specialization of call for Reg64
806 void call(Reg64 target
, CallArg ca
= CallArg::Internal
) {
807 mr(reg::r12
, target
);
813 //////////////////////////////////////////////////////////////////////
814 // Auxiliary for loading immediates in the best way
816 void limmediate(const Reg64
& rt
,
818 ImmType immt
= ImmType::TocOnly
,
819 bool immMayChange
= false);
821 // Auxiliary for loading a complete 64bits immediate into a register
822 void li64(const Reg64
& rt
, int64_t imm64
, bool fixedSize
= false);
824 // Auxiliary for loading a complete 64bits immediate into a register from TOC
825 void li64TOC (const Reg64
& rt
, int64_t imm64
,
826 ImmType immt
, bool immMayChange
);
828 // Auxiliary for loading a 32bits immediate into a register
829 void li32 (const Reg64
& rt
, int32_t imm32
);
831 void emitNop(int nbytes
) {
832 assert((nbytes
% 4 == 0) && "This arch supports only 4 bytes alignment");
833 for (; nbytes
> 0; nbytes
-= 4) nop();
836 // Secure high level instruction emitter
837 void Emit(PPC64Instr instruction
){
838 assert(codeBlock
.canEmit(sizeof(instruction
)));
839 assert(sizeof(instruction
) == sizeof(uint32_t));
843 // Can be used to generate or force a unimplemented opcode exception
844 void unimplemented();
846 //////////////////////////////////////////////////////////////////////
849 * Patch a branch to the correct target.
851 * It decodes the branch @jmp to decide whether it's an absolute branch or an
852 * offset branch and patches it properly.
854 static void patchBranch(CodeAddress jmp
, CodeAddress dest
);
855 static void patchAbsolute(CodeAddress jmp
, CodeAddress dest
);
857 //////////////////////////////////////////////////////////////////////
861 // type instruction emitters
862 // TODO(rcardoso): try remove cast for uint32_t
863 // TODO(rcardoso): make those functions inline
864 void EmitXOForm(const uint8_t op
,
872 // GP Register cannot be greater than 31
873 assert(static_cast<uint32_t>(rb
) < 32);
874 assert(static_cast<uint32_t>(ra
) < 32);
875 assert(static_cast<uint32_t>(rt
) < 32);
877 XO_form_t xo_formater
{{
881 static_cast<uint32_t>(rb
),
882 static_cast<uint32_t>(ra
),
883 static_cast<uint32_t>(rt
),
887 dword(xo_formater
.instruction
);
890 void EmitDForm(const uint8_t op
,
895 // GP Register cannot be greater than 31
896 assert(static_cast<uint32_t>(rt
) < 32);
897 assert(static_cast<uint32_t>(ra
) < 32);
899 D_form_t d_formater
{{
900 static_cast<uint32_t>(imm
),
901 static_cast<uint32_t>(ra
),
902 static_cast<uint32_t>(rt
),
906 dword(d_formater
.instruction
);
909 void EmitIForm(const uint8_t op
,
914 I_form_t i_formater
{{
921 dword(i_formater
.instruction
);
924 void EmitBForm(const uint8_t op
,
930 B_form_t b_formater
{{
939 dword(b_formater
.instruction
);
942 void EmitSCForm(const uint8_t op
,
943 const uint16_t lev
) {
944 SC_form_t sc_formater
{{
950 dword(sc_formater
.instruction
);
953 void EmitXForm(const uint8_t op
,
960 // GP Register cannot be greater than 31
961 assert(static_cast<uint32_t>(rb
) < 32);
962 assert(static_cast<uint32_t>(ra
) < 32);
963 assert(static_cast<uint32_t>(rt
) < 32);
965 X_form_t x_formater
{{
968 static_cast<uint32_t>(rb
),
969 static_cast<uint32_t>(ra
),
970 static_cast<uint32_t>(rt
),
974 dword(x_formater
.instruction
);
977 void EmitXForm(const uint8_t op
,
984 X_form_t x_formater
{{
987 static_cast<uint32_t>(rb
),
988 static_cast<uint32_t>(ra
),
989 static_cast<uint32_t>(rt
),
993 dword(x_formater
.instruction
);
997 void EmitDSForm(const uint8_t op
,
1001 const uint16_t xop
) {
1003 // GP Register cannot be greater than 31
1004 assert(static_cast<uint32_t>(ra
) < 32);
1005 assert(static_cast<uint32_t>(rt
) < 32);
1006 assert(static_cast<uint16_t>(imm
<< 14) == 0);
1008 DS_form_t ds_formater
{{
1010 static_cast<uint32_t>(imm
) >> 2,
1011 static_cast<uint32_t>(ra
),
1012 static_cast<uint32_t>(rt
),
1016 dword(ds_formater
.instruction
);
1019 void EmitDQForm(const uint8_t op
,
1020 const RegNumber rtp
,
1024 // GP Register cannot be greater than 31
1025 assert(static_cast<uint32_t>(ra
) < 32);
1026 assert(static_cast<uint16_t>(imm
<< 12) == 0);
1028 DQ_form_t dq_formater
{{
1030 static_cast<uint32_t>(rtp
),
1031 static_cast<uint32_t>(ra
),
1032 static_cast<uint32_t>(imm
) >> 4,
1036 dword(dq_formater
.instruction
);
1040 void EmitXLForm(const uint8_t op
,
1045 const bool lk
= 0) {
1047 XL_form_t xl_formater
{{
1056 dword(xl_formater
.instruction
);
1059 void EmitAForm(const uint8_t op
,
1065 const bool rc
= 0) {
1067 // GP Register cannot be greater than 31
1068 assert(static_cast<uint32_t>(rt
) < 32);
1069 assert(static_cast<uint32_t>(ra
) < 32);
1070 assert(static_cast<uint32_t>(rb
) < 32);
1071 assert(static_cast<uint32_t>(bc
) < 32);
1073 A_form_t a_formater
{{
1076 static_cast<uint32_t>(bc
),
1077 static_cast<uint32_t>(rb
),
1078 static_cast<uint32_t>(ra
),
1079 static_cast<uint32_t>(rt
),
1083 dword(a_formater
.instruction
);
1086 void EmitMForm(const uint8_t op
,
1092 const bool rc
= 0) {
1094 // GP Register cannot be greater than 31
1095 assert(static_cast<uint32_t>(rb
) < 32);
1096 assert(static_cast<uint32_t>(ra
) < 32);
1097 assert(static_cast<uint32_t>(rb
) < 32);
1099 M_form_t m_formater
{{
1103 static_cast<uint32_t>(rb
),
1104 static_cast<uint32_t>(ra
),
1105 static_cast<uint32_t>(rs
),
1109 dword(m_formater
.instruction
);
1112 void EmitMDForm(const uint8_t op
,
1118 const bool rc
= 0) {
1120 // GP Register cannot be greater than 31
1121 assert(static_cast<uint32_t>(ra
) < 32);
1122 assert(static_cast<uint32_t>(rs
) < 32);
1124 MD_form_t md_formater
{{
1126 static_cast<uint32_t>(sh
>> 5), // sh5
1128 static_cast<uint32_t>(((mb
>> 5) | (mb
<< 1)) & 0x3F), // me5 || me0:4
1129 static_cast<uint32_t>(sh
& 0x1F), // sh0:4
1130 static_cast<uint32_t>(ra
),
1131 static_cast<uint32_t>(rs
),
1135 dword(md_formater
.instruction
);
1138 void EmitMDSForm(const uint8_t op
,
1144 const bool rc
= 0) {
1146 // GP Register cannot be greater than 31
1147 assert(static_cast<uint32_t>(rb
) < 32);
1148 assert(static_cast<uint32_t>(ra
) < 32);
1149 assert(static_cast<uint32_t>(rs
) < 32);
1151 MDS_form_t mds_formater
{{
1155 static_cast<uint32_t>(rb
),
1156 static_cast<uint32_t>(ra
),
1157 static_cast<uint32_t>(rs
),
1161 dword(mds_formater
.instruction
);
1164 void EmitXFXForm(const uint8_t op
,
1166 const SpecialReg spr
,
1168 const uint8_t rsv
= 0) {
1170 // GP Register cannot be greater than 31
1171 assert(static_cast<uint32_t>(rs
) < 32);
1173 XFX_form_t xfx_formater
{{
1176 (static_cast<uint32_t>(spr
) >> 5) & 0x1F,
1177 static_cast<uint32_t>(spr
) & 0x1F,
1178 static_cast<uint32_t>(rs
),
1182 dword(xfx_formater
.instruction
);
1184 void EmitXFXForm(const uint8_t op
,
1186 const uint16_t mask
,
1188 const uint8_t rsv
= 0) {
1190 // GP Register cannot be greater than 31
1191 assert(static_cast<uint32_t>(rs
) < 32);
1193 XFX_form_t xfx_formater
{{
1196 static_cast<uint32_t>((mask
) & 0x1f),
1197 static_cast<uint32_t>(((mask
) >> 5) & 0x1F),
1198 static_cast<uint32_t>(rs
),
1202 dword(xfx_formater
.instruction
);
1205 void EmitXX2Form(const uint8_t op
,
1212 XX2_form_t xx2_formater
{{
1216 static_cast<uint32_t>(b
),
1217 static_cast<uint32_t>(uim
& 0x3),
1218 static_cast<uint32_t>(t
),
1221 dword(xx2_formater
.instruction
);
1224 void EmitXX3Form(const uint8_t op
,
1232 XX3_form_t xx3_formater
{{
1237 static_cast<uint32_t>(b
),
1238 static_cast<uint32_t>(a
),
1239 static_cast<uint32_t>(t
),
1242 dword(xx3_formater
.instruction
);
1245 void EmitXX1Form(const uint8_t op
,
1252 // GP Register cannot be greater than 31
1253 assert(static_cast<uint32_t>(s
) < 32);
1254 assert(static_cast<uint32_t>(ra
) < 32);
1255 assert(static_cast<uint32_t>(rb
) < 32);
1257 XX1_form_t xx1_formater
{{
1260 static_cast<uint32_t>(rb
),
1261 static_cast<uint32_t>(ra
),
1262 static_cast<uint32_t>(s
),
1266 dword(xx1_formater
.instruction
);
1269 void EmitVXForm(const uint8_t op
,
1273 const uint16_t xo
) {
1275 assert(static_cast<uint32_t>(rt
) < 32);
1276 assert(static_cast<uint32_t>(ra
) < 32);
1277 assert(static_cast<uint32_t>(rb
) < 32);
1279 VX_form_t vx_formater
{{
1281 static_cast<uint32_t>(rb
),
1282 static_cast<uint32_t>(ra
),
1283 static_cast<uint32_t>(rt
),
1287 dword(vx_formater
.instruction
);
1289 //TODO(rcardoso): Unimplemented instruction formaters
1290 void EmitXSForm(const uint8_t op
,
1297 // GP Register cannot be greater than 31
1298 assert(static_cast<uint32_t>(rt
) < 32);
1299 assert(static_cast<uint32_t>(ra
) < 32);
1301 XS_form_t xs_formater
{{
1303 static_cast<uint32_t>(sh
>> 5),
1305 static_cast<uint32_t>(sh
& 0x1F),
1306 static_cast<uint32_t>(ra
),
1307 static_cast<uint32_t>(rt
),
1311 dword(xs_formater
.instruction
);
1315 HPHP::CodeBlock
& codeBlock
;
1317 // Low-level emitter functions.
1318 void dword(uint32_t dw
) {
1319 codeBlock
.dword(dw
);
1322 template <typename T
>
1324 return RegNumber(int(r
));
1328 } // namespace ppc64_asm