Don't use Aast.Any when marking expressions as type Tany
[hiphop-php.git] / hphp / ppc64-asm / asm-ppc64.h
blob005bdcc7efd04ed3cf2df88adc380928d172c0d3
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
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_
20 #include <cstdint>
21 #include <cassert>
22 #include <vector>
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"
31 namespace ppc64_asm {
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 {};
60 namespace reg {
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);
147 return nullptr;
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);
158 return nullptr;
160 inline const char* regname(RegSF) {
161 return "cr0";
163 #undef RNAME
166 //////////////////////////////////////////////////////////////////////
168 // Forward declaration to be used in Label
169 struct Assembler;
171 enum class ImmType {
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)
179 enum class LinkReg {
180 Save,
181 DoNotTouch
184 struct Label {
185 Label() : m_a(nullptr) , m_address(nullptr) {}
186 /* implicit */ Label(CodeAddress predefined) : m_a(nullptr) ,
187 m_address(predefined) {}
189 ~Label();
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,
197 BranchConditions bc,
198 LinkReg lr,
199 ImmType immt = ImmType::TocOnly,
200 bool immMayChange = false);
201 void asm_label(Assembler& a);
203 private:
204 struct JumpInfo {
205 Assembler* a;
206 CodeAddress addr;
209 void addJump(Assembler* a);
211 Assembler* m_a;
212 CodeAddress m_address;
213 std::vector<JumpInfo> m_toPatch;
217 * Class that represents a virtual TOC
219 struct VMTOC {
221 private:
222 // VMTOC is a singleton
223 VMTOC()
224 : m_tocvector(nullptr)
225 , m_last_elem_pos(0)
229 ~VMTOC();
231 public:
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);
270 private:
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;
287 struct Assembler {
289 friend struct Label;
291 explicit Assembler(HPHP::CodeBlock& cb) : codeBlock(cb) {}
292 ~Assembler(){}
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);
328 bool empty() const {
329 return codeBlock.empty();
332 void clear() {
333 codeBlock.clear();
336 bool canEmit(size_t nBytes) const {
337 assert(capacity() >= used());
338 return nBytes < (capacity() - used());
341 enum class SpecialReg {
342 XER = 1,
343 DSCR = 3,
344 LR = 8,
345 CTR = 9,
346 AMR = 13,
347 TFHAR = 128,
348 TFIAR = 129,
349 TEXASR = 130,
350 TEXASRU = 131,
351 VRSAVE = 256,
352 SPEFSCR = 512,
353 MMCR2 = 769,
354 MMCRA = 770,
355 PMC1 = 771,
356 PMC2 = 772,
357 PMC3 = 773,
358 PMC4 = 774,
359 PMC5 = 775,
360 PMC6 = 776,
361 MMCR0 = 779,
362 BESCRS = 800,
363 BESCRSU = 801,
364 BESCRR = 802,
365 BESCRRU = 803,
366 EBBHR = 804,
367 EBBRR = 805,
368 BESCR = 806,
369 TAR = 815,
370 PPR = 896,
371 PPR32 = 898
374 enum class CR {
375 CR0 = 0,
376 CR1 = 1,
377 CR2 = 2,
378 CR3 = 3,
379 CR4 = 4,
380 CR5 = 5,
381 CR6 = 6,
382 CR7 = 7,
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);
410 void bctrl();
411 void blr();
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,
424 bool rc = 0);
425 void fsub(const RegXMM& frt, const RegXMM& fra, const RegXMM& frb,
426 bool rc = 0);
427 void fmul(const RegXMM& frt, const RegXMM& fra, const RegXMM& frc,
428 bool rc = 0);
429 void fdiv(const RegXMM& frt, const RegXMM& fra, const RegXMM& frb,
430 bool rc = 0);
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
602 void bctr() {
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) {
610 addi(rt, ra, -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) {
622 cmpi(0, 1, ra, 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
627 cmpi(0, 0, ra, imm);
629 void cmpd(const Reg64& ra, const Reg64& rb) {
630 cmp(0, 1, ra, 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
635 cmp(0, 0, ra, rb);
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);
653 void trap() {
654 tw(31, Reg64(0), Reg64(0));
656 void nop() {
657 ori(Reg64(0),Reg64(0),0);
659 void mr(const Reg64& rs, const Reg64& ra) {
660 or(rs, ra, 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);
697 // Label variants
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);
708 void bl(Label& l) {
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) {
723 Label l(c);
724 l.branch(*this, bc, lr, addrMayChange);
727 void branchAuto(CodeAddress c,
728 ConditionCode cc,
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) {
746 Label l(c);
747 l.branchFar(*this, bc, lr, immt, immMayChange);
750 void branchFar(CodeAddress c,
751 ConditionCode cc,
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) {
767 BranchParams bp(cc);
768 bc(bp.bo(), bp.bi(), address);
771 //////////////////////////////////////////////////////////////////////
773 enum class CallArg {
774 // Saves TOC? | Smashable?
775 // --------------------------
776 Internal, // No | No
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);
796 } else {
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);
802 callEpilogue(ca);
805 // specialization of call for Reg64
806 void call(Reg64 target, CallArg ca = CallArg::Internal) {
807 mr(reg::r12, target);
808 mtctr(reg::r12);
809 bctrl();
810 callEpilogue(ca);
813 //////////////////////////////////////////////////////////////////////
814 // Auxiliary for loading immediates in the best way
816 void limmediate(const Reg64& rt,
817 int64_t imm64,
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));
840 dword(instruction);
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 //////////////////////////////////////////////////////////////////////
859 protected:
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,
865 const RegNumber rt,
866 const RegNumber ra,
867 const RegNumber rb,
868 const bool oe,
869 const uint16_t xop,
870 const bool rc = 0) {
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 {{
879 xop,
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,
891 const RegNumber rt,
892 const RegNumber ra,
893 const int16_t imm) {
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,
910 const uint32_t imm,
911 const bool aa = 0,
912 const bool lk = 0) {
914 I_form_t i_formater {{
917 imm >> 2,
921 dword(i_formater.instruction);
924 void EmitBForm(const uint8_t op,
925 const uint8_t bo,
926 const uint8_t bi,
927 const uint32_t bd,
928 const bool aa = 0,
929 const bool lk = 0) {
930 B_form_t b_formater {{
933 bd >> 2,
939 dword(b_formater.instruction);
942 void EmitSCForm(const uint8_t op,
943 const uint16_t lev) {
944 SC_form_t sc_formater {{
946 lev,
950 dword(sc_formater.instruction);
953 void EmitXForm(const uint8_t op,
954 const RegNumber rt,
955 const RegNumber ra,
956 const RegNumber rb,
957 const uint16_t xop,
958 const bool rc = 0){
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 {{
967 xop,
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,
978 const uint32_t rt,
979 const uint32_t ra,
980 const uint32_t rb,
981 const uint16_t xop,
982 const bool rc = 0){
984 X_form_t x_formater {{
986 xop,
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,
998 const RegNumber rt,
999 const RegNumber ra,
1000 const uint16_t imm,
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 {{
1009 xop,
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,
1021 const RegNumber ra,
1022 uint16_t imm){
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 {{
1029 0x0, //Reserved
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,
1041 const uint8_t bt,
1042 const uint8_t ba,
1043 const uint8_t bb,
1044 const uint16_t xop,
1045 const bool lk = 0) {
1047 XL_form_t xl_formater {{
1049 xop,
1056 dword(xl_formater.instruction);
1059 void EmitAForm(const uint8_t op,
1060 const RegNumber rt,
1061 const RegNumber ra,
1062 const RegNumber rb,
1063 const RegNumber bc,
1064 const uint16_t xop,
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 {{
1075 xop,
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,
1087 const RegNumber rs,
1088 const RegNumber ra,
1089 const RegNumber rb,
1090 const uint8_t mb,
1091 const uint8_t me,
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,
1113 const RegNumber rs,
1114 const RegNumber ra,
1115 const uint8_t sh,
1116 const uint8_t mb,
1117 const uint8_t xop,
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
1127 xop,
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,
1139 const RegNumber rs,
1140 const RegNumber ra,
1141 const RegNumber rb,
1142 const uint8_t mb,
1143 const uint8_t xop,
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 {{
1153 xop,
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,
1165 const RegNumber rs,
1166 const SpecialReg spr,
1167 const uint16_t xo,
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 {{
1174 rsv,
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,
1185 const RegNumber rs,
1186 const uint16_t mask,
1187 const uint16_t xo,
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 {{
1194 rsv,
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,
1206 const RegNumber t,
1207 const uint8_t uim,
1208 const RegNumber b,
1209 const uint16_t xo,
1210 const bool bx,
1211 const bool tx) {
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,
1225 const RegNumber t,
1226 const RegNumber a,
1227 const RegNumber b,
1228 const uint16_t xo,
1229 const bool ax,
1230 const bool bx,
1231 const bool tx) {
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,
1246 const RegNumber s,
1247 const RegNumber ra,
1248 const RegNumber rb,
1249 const uint16_t xo,
1250 const bool tx) {
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,
1270 const RegNumber rt,
1271 const RegNumber ra,
1272 const RegNumber rb,
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,
1291 const RegNumber rt,
1292 const RegNumber ra,
1293 const uint8_t sh,
1294 const uint16_t xop,
1295 const bool rc = 0){
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),
1304 xop,
1305 static_cast<uint32_t>(sh & 0x1F),
1306 static_cast<uint32_t>(ra),
1307 static_cast<uint32_t>(rt),
1311 dword(xs_formater.instruction);
1314 private:
1315 HPHP::CodeBlock& codeBlock;
1317 // Low-level emitter functions.
1318 void dword(uint32_t dw) {
1319 codeBlock.dword(dw);
1322 template <typename T>
1323 RegNumber rn(T r) {
1324 return RegNumber(int(r));
1328 } // namespace ppc64_asm
1330 #endif