src/lj_emit_x86.h - luajit-2.0-src

Data types defined

Functions defined

Macros defined

Source code

  1. /*
  2. ** x86/x64 instruction emitter.
  3. ** Copyright (C) 2005-2015 Mike Pall. See Copyright Notice in luajit.h
  4. */

  5. /* -- Emit basic instructions --------------------------------------------- */

  6. #define MODRM(mode, r1, r2)        ((MCode)((mode)+(((r1)&7)<<3)+((r2)&7)))

  7. #if LJ_64
  8. #define REXRB(p, rr, rb) \
  9.     { MCode rex = 0x40 + (((rr)>>1)&4) + (((rb)>>3)&1); \
  10.       if (rex != 0x40) *--(p) = rex; }
  11. #define FORCE_REX                0x200
  12. #define REX_64                        (FORCE_REX|0x080000)
  13. #else
  14. #define REXRB(p, rr, rb)        ((void)0)
  15. #define FORCE_REX                0
  16. #define REX_64                        0
  17. #endif

  18. #define emit_i8(as, i)                (*--as->mcp = (MCode)(i))
  19. #define emit_i32(as, i)                (*(int32_t *)(as->mcp-4) = (i), as->mcp -= 4)
  20. #define emit_u32(as, u)                (*(uint32_t *)(as->mcp-4) = (u), as->mcp -= 4)

  21. #define emit_x87op(as, xo) \
  22.   (*(uint16_t *)(as->mcp-2) = (uint16_t)(xo), as->mcp -= 2)

  23. /* op */
  24. static LJ_AINLINE MCode *emit_op(x86Op xo, Reg rr, Reg rb, Reg rx,
  25.                                  MCode *p, int delta)
  26. {
  27.   int n = (int8_t)xo;
  28. #if defined(__GNUC__)
  29.   if (__builtin_constant_p(xo) && n == -2)
  30.     p[delta-2] = (MCode)(xo >> 24);
  31.   else if (__builtin_constant_p(xo) && n == -3)
  32.     *(uint16_t *)(p+delta-3) = (uint16_t)(xo >> 16);
  33.   else
  34. #endif
  35.     *(uint32_t *)(p+delta-5) = (uint32_t)xo;
  36.   p += n + delta;
  37. #if LJ_64
  38.   {
  39.     uint32_t rex = 0x40 + ((rr>>1)&(4+(FORCE_REX>>1)))+((rx>>2)&2)+((rb>>3)&1);
  40.     if (rex != 0x40) {
  41.       rex |= (rr >> 16);
  42.       if (n == -4) { *p = (MCode)rex; rex = (MCode)(xo >> 8); }
  43.       else if ((xo & 0xffffff) == 0x6600fd) { *p = (MCode)rex; rex = 0x66; }
  44.       *--p = (MCode)rex;
  45.     }
  46.   }
  47. #else
  48.   UNUSED(rr); UNUSED(rb); UNUSED(rx);
  49. #endif
  50.   return p;
  51. }

  52. /* op + modrm */
  53. #define emit_opm(xo, mode, rr, rb, p, delta) \
  54.   (p[(delta)-1] = MODRM((mode), (rr), (rb)), \
  55.    emit_op((xo), (rr), (rb), 0, (p), (delta)))

  56. /* op + modrm + sib */
  57. #define emit_opmx(xo, mode, scale, rr, rb, rx, p) \
  58.   (p[-1] = MODRM((scale), (rx), (rb)), \
  59.    p[-2] = MODRM((mode), (rr), RID_ESP), \
  60.    emit_op((xo), (rr), (rb), (rx), (p), -1))

  61. /* op r1, r2 */
  62. static void emit_rr(ASMState *as, x86Op xo, Reg r1, Reg r2)
  63. {
  64.   MCode *p = as->mcp;
  65.   as->mcp = emit_opm(xo, XM_REG, r1, r2, p, 0);
  66. }

  67. #if LJ_64 && defined(LUA_USE_ASSERT)
  68. /* [addr] is sign-extended in x64 and must be in lower 2G (not 4G). */
  69. static int32_t ptr2addr(const void *p)
  70. {
  71.   lua_assert((uintptr_t)p < (uintptr_t)0x80000000);
  72.   return i32ptr(p);
  73. }
  74. #else
  75. #define ptr2addr(p)        (i32ptr((p)))
  76. #endif

  77. /* op r, [addr] */
  78. static void emit_rma(ASMState *as, x86Op xo, Reg rr, const void *addr)
  79. {
  80.   MCode *p = as->mcp;
  81.   *(int32_t *)(p-4) = ptr2addr(addr);
  82. #if LJ_64
  83.   p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
  84.   as->mcp = emit_opm(xo, XM_OFS0, rr, RID_ESP, p, -5);
  85. #else
  86.   as->mcp = emit_opm(xo, XM_OFS0, rr, RID_EBP, p, -4);
  87. #endif
  88. }

  89. /* op r, [base+ofs] */
  90. static void emit_rmro(ASMState *as, x86Op xo, Reg rr, Reg rb, int32_t ofs)
  91. {
  92.   MCode *p = as->mcp;
  93.   x86Mode mode;
  94.   if (ra_hasreg(rb)) {
  95.     if (ofs == 0 && (rb&7) != RID_EBP) {
  96.       mode = XM_OFS0;
  97.     } else if (checki8(ofs)) {
  98.       *--p = (MCode)ofs;
  99.       mode = XM_OFS8;
  100.     } else {
  101.       p -= 4;
  102.       *(int32_t *)p = ofs;
  103.       mode = XM_OFS32;
  104.     }
  105.     if ((rb&7) == RID_ESP)
  106.       *--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
  107.   } else {
  108.     *(int32_t *)(p-4) = ofs;
  109. #if LJ_64
  110.     p[-5] = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
  111.     p -= 5;
  112.     rb = RID_ESP;
  113. #else
  114.     p -= 4;
  115.     rb = RID_EBP;
  116. #endif
  117.     mode = XM_OFS0;
  118.   }
  119.   as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
  120. }

  121. /* op r, [base+idx*scale+ofs] */
  122. static void emit_rmrxo(ASMState *as, x86Op xo, Reg rr, Reg rb, Reg rx,
  123.                        x86Mode scale, int32_t ofs)
  124. {
  125.   MCode *p = as->mcp;
  126.   x86Mode mode;
  127.   if (ofs == 0 && (rb&7) != RID_EBP) {
  128.     mode = XM_OFS0;
  129.   } else if (checki8(ofs)) {
  130.     mode = XM_OFS8;
  131.     *--p = (MCode)ofs;
  132.   } else {
  133.     mode = XM_OFS32;
  134.     p -= 4;
  135.     *(int32_t *)p = ofs;
  136.   }
  137.   as->mcp = emit_opmx(xo, mode, scale, rr, rb, rx, p);
  138. }

  139. /* op r, i */
  140. static void emit_gri(ASMState *as, x86Group xg, Reg rb, int32_t i)
  141. {
  142.   MCode *p = as->mcp;
  143.   x86Op xo;
  144.   if (checki8(i)) {
  145.     *--p = (MCode)i;
  146.     xo = XG_TOXOi8(xg);
  147.   } else {
  148.     p -= 4;
  149.     *(int32_t *)p = i;
  150.     xo = XG_TOXOi(xg);
  151.   }
  152.   as->mcp = emit_opm(xo, XM_REG, (Reg)(xg & 7) | (rb & REX_64), rb, p, 0);
  153. }

  154. /* op [base+ofs], i */
  155. static void emit_gmroi(ASMState *as, x86Group xg, Reg rb, int32_t ofs,
  156.                        int32_t i)
  157. {
  158.   x86Op xo;
  159.   if (checki8(i)) {
  160.     emit_i8(as, i);
  161.     xo = XG_TOXOi8(xg);
  162.   } else {
  163.     emit_i32(as, i);
  164.     xo = XG_TOXOi(xg);
  165.   }
  166.   emit_rmro(as, xo, (Reg)(xg & 7), rb, ofs);
  167. }

  168. #define emit_shifti(as, xg, r, i) \
  169.   (emit_i8(as, (i)), emit_rr(as, XO_SHIFTi, (Reg)(xg), (r)))

  170. /* op r, rm/mrm */
  171. static void emit_mrm(ASMState *as, x86Op xo, Reg rr, Reg rb)
  172. {
  173.   MCode *p = as->mcp;
  174.   x86Mode mode = XM_REG;
  175.   if (rb == RID_MRM) {
  176.     rb = as->mrm.base;
  177.     if (rb == RID_NONE) {
  178.       rb = RID_EBP;
  179.       mode = XM_OFS0;
  180.       p -= 4;
  181.       *(int32_t *)p = as->mrm.ofs;
  182.       if (as->mrm.idx != RID_NONE)
  183.         goto mrmidx;
  184. #if LJ_64
  185.       *--p = MODRM(XM_SCALE1, RID_ESP, RID_EBP);
  186.       rb = RID_ESP;
  187. #endif
  188.     } else {
  189.       if (as->mrm.ofs == 0 && (rb&7) != RID_EBP) {
  190.         mode = XM_OFS0;
  191.       } else if (checki8(as->mrm.ofs)) {
  192.         *--p = (MCode)as->mrm.ofs;
  193.         mode = XM_OFS8;
  194.       } else {
  195.         p -= 4;
  196.         *(int32_t *)p = as->mrm.ofs;
  197.         mode = XM_OFS32;
  198.       }
  199.       if (as->mrm.idx != RID_NONE) {
  200.       mrmidx:
  201.         as->mcp = emit_opmx(xo, mode, as->mrm.scale, rr, rb, as->mrm.idx, p);
  202.         return;
  203.       }
  204.       if ((rb&7) == RID_ESP)
  205.         *--p = MODRM(XM_SCALE1, RID_ESP, RID_ESP);
  206.     }
  207.   }
  208.   as->mcp = emit_opm(xo, mode, rr, rb, p, 0);
  209. }

  210. /* op rm/mrm, i */
  211. static void emit_gmrmi(ASMState *as, x86Group xg, Reg rb, int32_t i)
  212. {
  213.   x86Op xo;
  214.   if (checki8(i)) {
  215.     emit_i8(as, i);
  216.     xo = XG_TOXOi8(xg);
  217.   } else {
  218.     emit_i32(as, i);
  219.     xo = XG_TOXOi(xg);
  220.   }
  221.   emit_mrm(as, xo, (Reg)(xg & 7) | (rb & REX_64), (rb & ~REX_64));
  222. }

  223. /* -- Emit loads/stores --------------------------------------------------- */

  224. /* mov [base+ofs], i */
  225. static void emit_movmroi(ASMState *as, Reg base, int32_t ofs, int32_t i)
  226. {
  227.   emit_i32(as, i);
  228.   emit_rmro(as, XO_MOVmi, 0, base, ofs);
  229. }

  230. /* mov [base+ofs], r */
  231. #define emit_movtomro(as, r, base, ofs) \
  232.   emit_rmro(as, XO_MOVto, (r), (base), (ofs))

  233. /* Get/set global_State fields. */
  234. #define emit_opgl(as, xo, r, field) \
  235.   emit_rma(as, (xo), (r), (void *)&J2G(as->J)->field)
  236. #define emit_getgl(as, r, field)        emit_opgl(as, XO_MOV, (r), field)
  237. #define emit_setgl(as, r, field)        emit_opgl(as, XO_MOVto, (r), field)

  238. #define emit_setvmstate(as, i) \
  239.   (emit_i32(as, i), emit_opgl(as, XO_MOVmi, 0, vmstate))

  240. /* mov r, i / xor r, r */
  241. static void emit_loadi(ASMState *as, Reg r, int32_t i)
  242. {
  243.   /* XOR r,r is shorter, but modifies the flags. This is bad for HIOP. */
  244.   if (i == 0 && !(LJ_32 && (IR(as->curins)->o == IR_HIOP ||
  245.                             (as->curins+1 < as->T->nins &&
  246.                              IR(as->curins+1)->o == IR_HIOP)))) {
  247.     emit_rr(as, XO_ARITH(XOg_XOR), r, r);
  248.   } else {
  249.     MCode *p = as->mcp;
  250.     *(int32_t *)(p-4) = i;
  251.     p[-5] = (MCode)(XI_MOVri+(r&7));
  252.     p -= 5;
  253.     REXRB(p, 0, r);
  254.     as->mcp = p;
  255.   }
  256. }

  257. /* mov r, addr */
  258. #define emit_loada(as, r, addr) \
  259.   emit_loadi(as, (r), ptr2addr((addr)))

  260. #if LJ_64
  261. /* mov r, imm64 or shorter 32 bit extended load. */
  262. static void emit_loadu64(ASMState *as, Reg r, uint64_t u64)
  263. {
  264.   if (checku32(u64)) {  /* 32 bit load clears upper 32 bits. */
  265.     emit_loadi(as, r, (int32_t)u64);
  266.   } else if (checki32((int64_t)u64)) {  /* Sign-extended 32 bit load. */
  267.     MCode *p = as->mcp;
  268.     *(int32_t *)(p-4) = (int32_t)u64;
  269.     as->mcp = emit_opm(XO_MOVmi, XM_REG, REX_64, r, p, -4);
  270.   } else/* Full-size 64 bit load. */
  271.     MCode *p = as->mcp;
  272.     *(uint64_t *)(p-8) = u64;
  273.     p[-9] = (MCode)(XI_MOVri+(r&7));
  274.     p[-10] = 0x48 + ((r>>3)&1);
  275.     p -= 10;
  276.     as->mcp = p;
  277.   }
  278. }
  279. #endif

  280. /* movsd r, [&tv->n] / xorps r, r */
  281. static void emit_loadn(ASMState *as, Reg r, cTValue *tv)
  282. {
  283.   if (tvispzero(tv))  /* Use xor only for +0. */
  284.     emit_rr(as, XO_XORPS, r, r);
  285.   else
  286.     emit_rma(as, XO_MOVSD, r, &tv->n);
  287. }

  288. /* -- Emit control-flow instructions -------------------------------------- */

  289. /* Label for short jumps. */
  290. typedef MCode *MCLabel;

  291. #if LJ_32 && LJ_HASFFI
  292. /* jmp short target */
  293. static void emit_sjmp(ASMState *as, MCLabel target)
  294. {
  295.   MCode *p = as->mcp;
  296.   ptrdiff_t delta = target - p;
  297.   lua_assert(delta == (int8_t)delta);
  298.   p[-1] = (MCode)(int8_t)delta;
  299.   p[-2] = XI_JMPs;
  300.   as->mcp = p - 2;
  301. }
  302. #endif

  303. /* jcc short target */
  304. static void emit_sjcc(ASMState *as, int cc, MCLabel target)
  305. {
  306.   MCode *p = as->mcp;
  307.   ptrdiff_t delta = target - p;
  308.   lua_assert(delta == (int8_t)delta);
  309.   p[-1] = (MCode)(int8_t)delta;
  310.   p[-2] = (MCode)(XI_JCCs+(cc&15));
  311.   as->mcp = p - 2;
  312. }

  313. /* jcc short (pending target) */
  314. static MCLabel emit_sjcc_label(ASMState *as, int cc)
  315. {
  316.   MCode *p = as->mcp;
  317.   p[-1] = 0;
  318.   p[-2] = (MCode)(XI_JCCs+(cc&15));
  319.   as->mcp = p - 2;
  320.   return p;
  321. }

  322. /* Fixup jcc short target. */
  323. static void emit_sfixup(ASMState *as, MCLabel source)
  324. {
  325.   source[-1] = (MCode)(as->mcp-source);
  326. }

  327. /* Return label pointing to current PC. */
  328. #define emit_label(as)                ((as)->mcp)

  329. /* Compute relative 32 bit offset for jump and call instructions. */
  330. static LJ_AINLINE int32_t jmprel(MCode *p, MCode *target)
  331. {
  332.   ptrdiff_t delta = target - p;
  333.   lua_assert(delta == (int32_t)delta);
  334.   return (int32_t)delta;
  335. }

  336. /* jcc target */
  337. static void emit_jcc(ASMState *as, int cc, MCode *target)
  338. {
  339.   MCode *p = as->mcp;
  340.   *(int32_t *)(p-4) = jmprel(p, target);
  341.   p[-5] = (MCode)(XI_JCCn+(cc&15));
  342.   p[-6] = 0x0f;
  343.   as->mcp = p - 6;
  344. }

  345. /* jmp target */
  346. static void emit_jmp(ASMState *as, MCode *target)
  347. {
  348.   MCode *p = as->mcp;
  349.   *(int32_t *)(p-4) = jmprel(p, target);
  350.   p[-5] = XI_JMP;
  351.   as->mcp = p - 5;
  352. }

  353. /* call target */
  354. static void emit_call_(ASMState *as, MCode *target)
  355. {
  356.   MCode *p = as->mcp;
  357. #if LJ_64
  358.   if (target-p != (int32_t)(target-p)) {
  359.     /* Assumes RID_RET is never an argument to calls and always clobbered. */
  360.     emit_rr(as, XO_GROUP5, XOg_CALL, RID_RET);
  361.     emit_loadu64(as, RID_RET, (uint64_t)target);
  362.     return;
  363.   }
  364. #endif
  365.   *(int32_t *)(p-4) = jmprel(p, target);
  366.   p[-5] = XI_CALL;
  367.   as->mcp = p - 5;
  368. }

  369. #define emit_call(as, f)        emit_call_(as, (MCode *)(void *)(f))

  370. /* -- Emit generic operations --------------------------------------------- */

  371. /* Use 64 bit operations to handle 64 bit IR types. */
  372. #if LJ_64
  373. #define REX_64IR(ir, r)                ((r) + (irt_is64((ir)->t) ? REX_64 : 0))
  374. #else
  375. #define REX_64IR(ir, r)                (r)
  376. #endif

  377. /* Generic move between two regs. */
  378. static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
  379. {
  380.   UNUSED(ir);
  381.   if (dst < RID_MAX_GPR)
  382.     emit_rr(as, XO_MOV, REX_64IR(ir, dst), src);
  383.   else
  384.     emit_rr(as, XO_MOVAPS, dst, src);
  385. }

  386. /* Generic load of register with base and (small) offset address. */
  387. static void emit_loadofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs)
  388. {
  389.   if (r < RID_MAX_GPR)
  390.     emit_rmro(as, XO_MOV, REX_64IR(ir, r), base, ofs);
  391.   else
  392.     emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSD : XO_MOVSS, r, base, ofs);
  393. }

  394. /* Generic store of register with base and (small) offset address. */
  395. static void emit_storeofs(ASMState *as, IRIns *ir, Reg r, Reg base, int32_t ofs)
  396. {
  397.   if (r < RID_MAX_GPR)
  398.     emit_rmro(as, XO_MOVto, REX_64IR(ir, r), base, ofs);
  399.   else
  400.     emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, r, base, ofs);
  401. }

  402. /* Add offset to pointer. */
  403. static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
  404. {
  405.   if (ofs) {
  406.     if ((as->flags & JIT_F_LEA_AGU))
  407.       emit_rmro(as, XO_LEA, r, r, ofs);
  408.     else
  409.       emit_gri(as, XG_ARITHi(XOg_ADD), r, ofs);
  410.   }
  411. }

  412. #define emit_spsub(as, ofs)        emit_addptr(as, RID_ESP|REX_64, -(ofs))

  413. /* Prefer rematerialization of BASE/L from global_State over spills. */
  414. #define emit_canremat(ref)        ((ref) <= REF_BASE)