diff options
Diffstat (limited to 'src/lj_asm_mips.h')
-rw-r--r-- | src/lj_asm_mips.h | 349 |
1 files changed, 97 insertions, 252 deletions
diff --git a/src/lj_asm_mips.h b/src/lj_asm_mips.h index 9fe7c9c3..3d061eb4 100644 --- a/src/lj_asm_mips.h +++ b/src/lj_asm_mips.h | |||
@@ -226,7 +226,7 @@ static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref, | |||
226 | /* Generate a call to a C function. */ | 226 | /* Generate a call to a C function. */ |
227 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | 227 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) |
228 | { | 228 | { |
229 | uint32_t n, nargs = CCI_NARGS(ci); | 229 | uint32_t n, nargs = CCI_XNARGS(ci); |
230 | int32_t ofs = 16; | 230 | int32_t ofs = 16; |
231 | Reg gpr, fpr = REGARG_FIRSTFPR; | 231 | Reg gpr, fpr = REGARG_FIRSTFPR; |
232 | if ((void *)ci->func) | 232 | if ((void *)ci->func) |
@@ -326,15 +326,6 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
326 | } | 326 | } |
327 | } | 327 | } |
328 | 328 | ||
329 | static void asm_call(ASMState *as, IRIns *ir) | ||
330 | { | ||
331 | IRRef args[CCI_NARGS_MAX]; | ||
332 | const CCallInfo *ci = &lj_ir_callinfo[ir->op2]; | ||
333 | asm_collectargs(as, ir, ci, args); | ||
334 | asm_setupresult(as, ir, ci); | ||
335 | asm_gencall(as, ci, args); | ||
336 | } | ||
337 | |||
338 | static void asm_callx(ASMState *as, IRIns *ir) | 329 | static void asm_callx(ASMState *as, IRIns *ir) |
339 | { | 330 | { |
340 | IRRef args[CCI_NARGS_MAX*2]; | 331 | IRRef args[CCI_NARGS_MAX*2]; |
@@ -362,16 +353,6 @@ static void asm_callx(ASMState *as, IRIns *ir) | |||
362 | asm_gencall(as, &ci, args); | 353 | asm_gencall(as, &ci, args); |
363 | } | 354 | } |
364 | 355 | ||
365 | static void asm_callid(ASMState *as, IRIns *ir, IRCallID id) | ||
366 | { | ||
367 | const CCallInfo *ci = &lj_ir_callinfo[id]; | ||
368 | IRRef args[2]; | ||
369 | args[0] = ir->op1; | ||
370 | args[1] = ir->op2; | ||
371 | asm_setupresult(as, ir, ci); | ||
372 | asm_gencall(as, ci, args); | ||
373 | } | ||
374 | |||
375 | static void asm_callround(ASMState *as, IRIns *ir, IRCallID id) | 356 | static void asm_callround(ASMState *as, IRIns *ir, IRCallID id) |
376 | { | 357 | { |
377 | /* The modified regs must match with the *.dasc implementation. */ | 358 | /* The modified regs must match with the *.dasc implementation. */ |
@@ -519,28 +500,6 @@ static void asm_conv(ASMState *as, IRIns *ir) | |||
519 | } | 500 | } |
520 | } | 501 | } |
521 | 502 | ||
522 | #if LJ_HASFFI | ||
523 | static void asm_conv64(ASMState *as, IRIns *ir) | ||
524 | { | ||
525 | IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK); | ||
526 | IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH); | ||
527 | IRCallID id; | ||
528 | const CCallInfo *ci; | ||
529 | IRRef args[2]; | ||
530 | args[LJ_BE?0:1] = ir->op1; | ||
531 | args[LJ_BE?1:0] = (ir-1)->op1; | ||
532 | if (st == IRT_NUM || st == IRT_FLOAT) { | ||
533 | id = IRCALL_fp64_d2l + ((st == IRT_FLOAT) ? 2 : 0) + (dt - IRT_I64); | ||
534 | ir--; | ||
535 | } else { | ||
536 | id = IRCALL_fp64_l2d + ((dt == IRT_FLOAT) ? 2 : 0) + (st - IRT_I64); | ||
537 | } | ||
538 | ci = &lj_ir_callinfo[id]; | ||
539 | asm_setupresult(as, ir, ci); | ||
540 | asm_gencall(as, ci, args); | ||
541 | } | ||
542 | #endif | ||
543 | |||
544 | static void asm_strto(ASMState *as, IRIns *ir) | 503 | static void asm_strto(ASMState *as, IRIns *ir) |
545 | { | 504 | { |
546 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; | 505 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; |
@@ -557,6 +516,8 @@ static void asm_strto(ASMState *as, IRIns *ir) | |||
557 | RID_SP, sps_scale(ir->s)); | 516 | RID_SP, sps_scale(ir->s)); |
558 | } | 517 | } |
559 | 518 | ||
519 | /* -- Memory references --------------------------------------------------- */ | ||
520 | |||
560 | /* Get pointer to TValue. */ | 521 | /* Get pointer to TValue. */ |
561 | static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) | 522 | static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) |
562 | { | 523 | { |
@@ -580,27 +541,6 @@ static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) | |||
580 | } | 541 | } |
581 | } | 542 | } |
582 | 543 | ||
583 | static void asm_tostr(ASMState *as, IRIns *ir) | ||
584 | { | ||
585 | IRRef args[2]; | ||
586 | args[0] = ASMREF_L; | ||
587 | as->gcsteps++; | ||
588 | if (irt_isnum(IR(ir->op1)->t) || (ir+1)->o == IR_HIOP) { | ||
589 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromnum]; | ||
590 | args[1] = ASMREF_TMP1; /* const lua_Number * */ | ||
591 | asm_setupresult(as, ir, ci); /* GCstr * */ | ||
592 | asm_gencall(as, ci, args); | ||
593 | asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op1); | ||
594 | } else { | ||
595 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromint]; | ||
596 | args[1] = ir->op1; /* int32_t k */ | ||
597 | asm_setupresult(as, ir, ci); /* GCstr * */ | ||
598 | asm_gencall(as, ci, args); | ||
599 | } | ||
600 | } | ||
601 | |||
602 | /* -- Memory references --------------------------------------------------- */ | ||
603 | |||
604 | static void asm_aref(ASMState *as, IRIns *ir) | 544 | static void asm_aref(ASMState *as, IRIns *ir) |
605 | { | 545 | { |
606 | Reg dest = ra_dest(as, ir, RSET_GPR); | 546 | Reg dest = ra_dest(as, ir, RSET_GPR); |
@@ -630,7 +570,7 @@ static void asm_aref(ASMState *as, IRIns *ir) | |||
630 | ** } while ((n = nextnode(n))); | 570 | ** } while ((n = nextnode(n))); |
631 | ** return niltv(L); | 571 | ** return niltv(L); |
632 | */ | 572 | */ |
633 | static void asm_href(ASMState *as, IRIns *ir) | 573 | static void asm_href(ASMState *as, IRIns *ir, IROp merge) |
634 | { | 574 | { |
635 | RegSet allow = RSET_GPR; | 575 | RegSet allow = RSET_GPR; |
636 | int destused = ra_used(ir); | 576 | int destused = ra_used(ir); |
@@ -656,37 +596,42 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
656 | tmp2 = ra_scratch(as, allow); | 596 | tmp2 = ra_scratch(as, allow); |
657 | rset_clear(allow, tmp2); | 597 | rset_clear(allow, tmp2); |
658 | 598 | ||
659 | /* Key not found in chain: load niltv. */ | 599 | /* Key not found in chain: jump to exit (if merged) or load niltv. */ |
660 | l_end = emit_label(as); | 600 | l_end = emit_label(as); |
661 | if (destused) | 601 | as->invmcp = NULL; |
602 | if (merge == IR_NE) | ||
603 | asm_guard(as, MIPSI_B, RID_ZERO, RID_ZERO); | ||
604 | else if (destused) | ||
662 | emit_loada(as, dest, niltvg(J2G(as->J))); | 605 | emit_loada(as, dest, niltvg(J2G(as->J))); |
663 | else | ||
664 | *--as->mcp = MIPSI_NOP; | ||
665 | /* Follow hash chain until the end. */ | 606 | /* Follow hash chain until the end. */ |
666 | emit_move(as, dest, tmp1); | 607 | emit_move(as, dest, tmp2); |
667 | l_loop = --as->mcp; | 608 | l_loop = --as->mcp; |
668 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, next)); | 609 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, next)); |
669 | l_next = emit_label(as); | 610 | l_next = emit_label(as); |
670 | 611 | ||
671 | /* Type and value comparison. */ | 612 | /* Type and value comparison. */ |
613 | if (merge == IR_EQ) { /* Must match asm_guard(). */ | ||
614 | emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); | ||
615 | l_end = asm_exitstub_addr(as); | ||
616 | } | ||
672 | if (irt_isnum(kt)) { | 617 | if (irt_isnum(kt)) { |
673 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); | 618 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); |
674 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); | 619 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); |
675 | emit_tg(as, MIPSI_MFC1, tmp1, key+1); | 620 | *--as->mcp = MIPSI_NOP; /* Avoid NaN comparison overhead. */ |
676 | emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next); | 621 | emit_branch(as, MIPSI_BEQ, tmp2, RID_ZERO, l_next); |
677 | emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM); | 622 | emit_tsi(as, MIPSI_SLTIU, tmp2, tmp2, (int32_t)LJ_TISNUM); |
678 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); | 623 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); |
679 | } else { | 624 | } else { |
680 | if (irt_ispri(kt)) { | 625 | if (irt_ispri(kt)) { |
681 | emit_branch(as, MIPSI_BEQ, tmp1, type, l_end); | 626 | emit_branch(as, MIPSI_BEQ, tmp2, type, l_end); |
682 | } else { | 627 | } else { |
683 | emit_branch(as, MIPSI_BEQ, tmp2, key, l_end); | 628 | emit_branch(as, MIPSI_BEQ, tmp1, key, l_end); |
684 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); | 629 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.gcr)); |
685 | emit_branch(as, MIPSI_BNE, tmp1, type, l_next); | 630 | emit_branch(as, MIPSI_BNE, tmp2, type, l_next); |
686 | } | 631 | } |
687 | } | 632 | } |
688 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it)); | 633 | emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.it)); |
689 | *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); | 634 | *l_loop = MIPSI_BNE | MIPSF_S(tmp2) | ((as->mcp-l_loop-1) & 0xffffu); |
690 | 635 | ||
691 | /* Load main position relative to tab->node into dest. */ | 636 | /* Load main position relative to tab->node into dest. */ |
692 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; | 637 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; |
@@ -776,20 +721,6 @@ nolo: | |||
776 | emit_tsi(as, MIPSI_ADDU, dest, node, ra_allock(as, ofs, allow)); | 721 | emit_tsi(as, MIPSI_ADDU, dest, node, ra_allock(as, ofs, allow)); |
777 | } | 722 | } |
778 | 723 | ||
779 | static void asm_newref(ASMState *as, IRIns *ir) | ||
780 | { | ||
781 | if (ir->r != RID_SINK) { | ||
782 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_newkey]; | ||
783 | IRRef args[3]; | ||
784 | args[0] = ASMREF_L; /* lua_State *L */ | ||
785 | args[1] = ir->op1; /* GCtab *t */ | ||
786 | args[2] = ASMREF_TMP1; /* cTValue *key */ | ||
787 | asm_setupresult(as, ir, ci); /* TValue * */ | ||
788 | asm_gencall(as, ci, args); | ||
789 | asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op2); | ||
790 | } | ||
791 | } | ||
792 | |||
793 | static void asm_uref(ASMState *as, IRIns *ir) | 724 | static void asm_uref(ASMState *as, IRIns *ir) |
794 | { | 725 | { |
795 | /* NYI: Check that UREFO is still open and not aliasing a slot. */ | 726 | /* NYI: Check that UREFO is still open and not aliasing a slot. */ |
@@ -918,7 +849,7 @@ static void asm_xload(ASMState *as, IRIns *ir) | |||
918 | asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); | 849 | asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); |
919 | } | 850 | } |
920 | 851 | ||
921 | static void asm_xstore(ASMState *as, IRIns *ir, int32_t ofs) | 852 | static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) |
922 | { | 853 | { |
923 | if (ir->r != RID_SINK) { | 854 | if (ir->r != RID_SINK) { |
924 | Reg src = ra_alloc1z(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 855 | Reg src = ra_alloc1z(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); |
@@ -927,6 +858,8 @@ static void asm_xstore(ASMState *as, IRIns *ir, int32_t ofs) | |||
927 | } | 858 | } |
928 | } | 859 | } |
929 | 860 | ||
861 | #define asm_xstore(as, ir) asm_xstore_(as, ir, 0) | ||
862 | |||
930 | static void asm_ahuvload(ASMState *as, IRIns *ir) | 863 | static void asm_ahuvload(ASMState *as, IRIns *ir) |
931 | { | 864 | { |
932 | IRType1 t = ir->t; | 865 | IRType1 t = ir->t; |
@@ -1002,7 +935,7 @@ static void asm_sload(ASMState *as, IRIns *ir) | |||
1002 | if (irt_isint(t)) { | 935 | if (irt_isint(t)) { |
1003 | Reg tmp = ra_scratch(as, RSET_FPR); | 936 | Reg tmp = ra_scratch(as, RSET_FPR); |
1004 | emit_tg(as, MIPSI_MFC1, dest, tmp); | 937 | emit_tg(as, MIPSI_MFC1, dest, tmp); |
1005 | emit_fg(as, MIPSI_CVT_W_D, tmp, tmp); | 938 | emit_fg(as, MIPSI_TRUNC_W_D, tmp, tmp); |
1006 | dest = tmp; | 939 | dest = tmp; |
1007 | t.irt = IRT_NUM; /* Check for original type. */ | 940 | t.irt = IRT_NUM; /* Check for original type. */ |
1008 | } else { | 941 | } else { |
@@ -1042,19 +975,15 @@ dotypecheck: | |||
1042 | static void asm_cnew(ASMState *as, IRIns *ir) | 975 | static void asm_cnew(ASMState *as, IRIns *ir) |
1043 | { | 976 | { |
1044 | CTState *cts = ctype_ctsG(J2G(as->J)); | 977 | CTState *cts = ctype_ctsG(J2G(as->J)); |
1045 | CTypeID ctypeid = (CTypeID)IR(ir->op1)->i; | 978 | CTypeID id = (CTypeID)IR(ir->op1)->i; |
1046 | CTSize sz = (ir->o == IR_CNEWI || ir->op2 == REF_NIL) ? | 979 | CTSize sz; |
1047 | lj_ctype_size(cts, ctypeid) : (CTSize)IR(ir->op2)->i; | 980 | CTInfo info = lj_ctype_info(cts, id, &sz); |
1048 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; | 981 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; |
1049 | IRRef args[2]; | 982 | IRRef args[4]; |
1050 | RegSet allow = (RSET_GPR & ~RSET_SCRATCH); | ||
1051 | RegSet drop = RSET_SCRATCH; | 983 | RegSet drop = RSET_SCRATCH; |
1052 | lua_assert(sz != CTSIZE_INVALID); | 984 | lua_assert(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL)); |
1053 | 985 | ||
1054 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1055 | args[1] = ASMREF_TMP1; /* MSize size */ | ||
1056 | as->gcsteps++; | 986 | as->gcsteps++; |
1057 | |||
1058 | if (ra_hasreg(ir->r)) | 987 | if (ra_hasreg(ir->r)) |
1059 | rset_clear(drop, ir->r); /* Dest reg handled below. */ | 988 | rset_clear(drop, ir->r); /* Dest reg handled below. */ |
1060 | ra_evictset(as, drop); | 989 | ra_evictset(as, drop); |
@@ -1063,6 +992,7 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
1063 | 992 | ||
1064 | /* Initialize immutable cdata object. */ | 993 | /* Initialize immutable cdata object. */ |
1065 | if (ir->o == IR_CNEWI) { | 994 | if (ir->o == IR_CNEWI) { |
995 | RegSet allow = (RSET_GPR & ~RSET_SCRATCH); | ||
1066 | int32_t ofs = sizeof(GCcdata); | 996 | int32_t ofs = sizeof(GCcdata); |
1067 | lua_assert(sz == 4 || sz == 8); | 997 | lua_assert(sz == 4 || sz == 8); |
1068 | if (sz == 8) { | 998 | if (sz == 8) { |
@@ -1077,12 +1007,24 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
1077 | if (ofs == sizeof(GCcdata)) break; | 1007 | if (ofs == sizeof(GCcdata)) break; |
1078 | ofs -= 4; if (LJ_BE) ir++; else ir--; | 1008 | ofs -= 4; if (LJ_BE) ir++; else ir--; |
1079 | } | 1009 | } |
1010 | } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ | ||
1011 | ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; | ||
1012 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1013 | args[1] = ir->op1; /* CTypeID id */ | ||
1014 | args[2] = ir->op2; /* CTSize sz */ | ||
1015 | args[3] = ASMREF_TMP1; /* CTSize align */ | ||
1016 | asm_gencall(as, ci, args); | ||
1017 | emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); | ||
1018 | return; | ||
1080 | } | 1019 | } |
1020 | |||
1081 | /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ | 1021 | /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ |
1082 | emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); | 1022 | emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); |
1083 | emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); | 1023 | emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); |
1084 | emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA); | 1024 | emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA); |
1085 | emit_ti(as, MIPSI_LI, RID_TMP, ctypeid); /* Lower 16 bit used. Sign-ext ok. */ | 1025 | emit_ti(as, MIPSI_LI, RID_TMP, id); /* Lower 16 bit used. Sign-ext ok. */ |
1026 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1027 | args[1] = ASMREF_TMP1; /* MSize size */ | ||
1086 | asm_gencall(as, ci, args); | 1028 | asm_gencall(as, ci, args); |
1087 | ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), | 1029 | ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), |
1088 | ra_releasetmp(as, ASMREF_TMP1)); | 1030 | ra_releasetmp(as, ASMREF_TMP1)); |
@@ -1152,23 +1094,16 @@ static void asm_fpunary(ASMState *as, IRIns *ir, MIPSIns mi) | |||
1152 | emit_fg(as, mi, dest, left); | 1094 | emit_fg(as, mi, dest, left); |
1153 | } | 1095 | } |
1154 | 1096 | ||
1155 | static int asm_fpjoin_pow(ASMState *as, IRIns *ir) | 1097 | static void asm_fpmath(ASMState *as, IRIns *ir) |
1156 | { | 1098 | { |
1157 | IRIns *irp = IR(ir->op1); | 1099 | if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) |
1158 | if (irp == ir-1 && irp->o == IR_MUL && !ra_used(irp)) { | 1100 | return; |
1159 | IRIns *irpp = IR(irp->op1); | 1101 | if (ir->op2 <= IRFPM_TRUNC) |
1160 | if (irpp == ir-2 && irpp->o == IR_FPMATH && | 1102 | asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2); |
1161 | irpp->op2 == IRFPM_LOG2 && !ra_used(irpp)) { | 1103 | else if (ir->op2 == IRFPM_SQRT) |
1162 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_pow]; | 1104 | asm_fpunary(as, ir, MIPSI_SQRT_D); |
1163 | IRRef args[2]; | 1105 | else |
1164 | args[0] = irpp->op1; | 1106 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); |
1165 | args[1] = irp->op2; | ||
1166 | asm_setupresult(as, ir, ci); | ||
1167 | asm_gencall(as, ci, args); | ||
1168 | return 1; | ||
1169 | } | ||
1170 | } | ||
1171 | return 0; | ||
1172 | } | 1107 | } |
1173 | 1108 | ||
1174 | static void asm_add(ASMState *as, IRIns *ir) | 1109 | static void asm_add(ASMState *as, IRIns *ir) |
@@ -1214,6 +1149,10 @@ static void asm_mul(ASMState *as, IRIns *ir) | |||
1214 | } | 1149 | } |
1215 | } | 1150 | } |
1216 | 1151 | ||
1152 | #define asm_div(as, ir) asm_fparith(as, ir, MIPSI_DIV_D) | ||
1153 | #define asm_mod(as, ir) asm_callid(as, ir, IRCALL_lj_vm_modi) | ||
1154 | #define asm_pow(as, ir) asm_callid(as, ir, IRCALL_lj_vm_powi) | ||
1155 | |||
1217 | static void asm_neg(ASMState *as, IRIns *ir) | 1156 | static void asm_neg(ASMState *as, IRIns *ir) |
1218 | { | 1157 | { |
1219 | if (irt_isnum(ir->t)) { | 1158 | if (irt_isnum(ir->t)) { |
@@ -1225,6 +1164,10 @@ static void asm_neg(ASMState *as, IRIns *ir) | |||
1225 | } | 1164 | } |
1226 | } | 1165 | } |
1227 | 1166 | ||
1167 | #define asm_abs(as, ir) asm_fpunary(as, ir, MIPSI_ABS_D) | ||
1168 | #define asm_atan2(as, ir) asm_callid(as, ir, IRCALL_atan2) | ||
1169 | #define asm_ldexp(as, ir) asm_callid(as, ir, IRCALL_ldexp) | ||
1170 | |||
1228 | static void asm_arithov(ASMState *as, IRIns *ir) | 1171 | static void asm_arithov(ASMState *as, IRIns *ir) |
1229 | { | 1172 | { |
1230 | Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR); | 1173 | Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR); |
@@ -1258,13 +1201,21 @@ static void asm_arithov(ASMState *as, IRIns *ir) | |||
1258 | emit_move(as, RID_TMP, dest == left ? left : right); | 1201 | emit_move(as, RID_TMP, dest == left ? left : right); |
1259 | } | 1202 | } |
1260 | 1203 | ||
1204 | #define asm_addov(as, ir) asm_arithov(as, ir) | ||
1205 | #define asm_subov(as, ir) asm_arithov(as, ir) | ||
1206 | |||
1261 | static void asm_mulov(ASMState *as, IRIns *ir) | 1207 | static void asm_mulov(ASMState *as, IRIns *ir) |
1262 | { | 1208 | { |
1263 | #if LJ_DUALNUM | 1209 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1264 | #error "NYI: MULOV" | 1210 | Reg tmp, right, left = ra_alloc2(as, ir, RSET_GPR); |
1265 | #else | 1211 | right = (left >> 8); left &= 255; |
1266 | UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused in single-number mode. */ | 1212 | tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, left), |
1267 | #endif | 1213 | right), dest)); |
1214 | asm_guard(as, MIPSI_BNE, RID_TMP, tmp); | ||
1215 | emit_dta(as, MIPSI_SRA, RID_TMP, dest, 31); | ||
1216 | emit_dst(as, MIPSI_MFHI, tmp, 0, 0); | ||
1217 | emit_dst(as, MIPSI_MFLO, dest, 0, 0); | ||
1218 | emit_dst(as, MIPSI_MULT, 0, left, right); | ||
1268 | } | 1219 | } |
1269 | 1220 | ||
1270 | #if LJ_HASFFI | 1221 | #if LJ_HASFFI |
@@ -1351,7 +1302,7 @@ static void asm_neg64(ASMState *as, IRIns *ir) | |||
1351 | } | 1302 | } |
1352 | #endif | 1303 | #endif |
1353 | 1304 | ||
1354 | static void asm_bitnot(ASMState *as, IRIns *ir) | 1305 | static void asm_bnot(ASMState *as, IRIns *ir) |
1355 | { | 1306 | { |
1356 | Reg left, right, dest = ra_dest(as, ir, RSET_GPR); | 1307 | Reg left, right, dest = ra_dest(as, ir, RSET_GPR); |
1357 | IRIns *irl = IR(ir->op1); | 1308 | IRIns *irl = IR(ir->op1); |
@@ -1365,7 +1316,7 @@ static void asm_bitnot(ASMState *as, IRIns *ir) | |||
1365 | emit_dst(as, MIPSI_NOR, dest, left, right); | 1316 | emit_dst(as, MIPSI_NOR, dest, left, right); |
1366 | } | 1317 | } |
1367 | 1318 | ||
1368 | static void asm_bitswap(ASMState *as, IRIns *ir) | 1319 | static void asm_bswap(ASMState *as, IRIns *ir) |
1369 | { | 1320 | { |
1370 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1321 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1371 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); | 1322 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); |
@@ -1401,6 +1352,10 @@ static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | |||
1401 | emit_dst(as, mi, dest, left, right); | 1352 | emit_dst(as, mi, dest, left, right); |
1402 | } | 1353 | } |
1403 | 1354 | ||
1355 | #define asm_band(as, ir) asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI) | ||
1356 | #define asm_bor(as, ir) asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI) | ||
1357 | #define asm_bxor(as, ir) asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI) | ||
1358 | |||
1404 | static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | 1359 | static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) |
1405 | { | 1360 | { |
1406 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1361 | Reg dest = ra_dest(as, ir, RSET_GPR); |
@@ -1414,7 +1369,12 @@ static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | |||
1414 | } | 1369 | } |
1415 | } | 1370 | } |
1416 | 1371 | ||
1417 | static void asm_bitror(ASMState *as, IRIns *ir) | 1372 | #define asm_bshl(as, ir) asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL) |
1373 | #define asm_bshr(as, ir) asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL) | ||
1374 | #define asm_bsar(as, ir) asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA) | ||
1375 | #define asm_brol(as, ir) lua_assert(0) | ||
1376 | |||
1377 | static void asm_bror(ASMState *as, IRIns *ir) | ||
1418 | { | 1378 | { |
1419 | if ((as->flags & JIT_F_MIPS32R2)) { | 1379 | if ((as->flags & JIT_F_MIPS32R2)) { |
1420 | asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR); | 1380 | asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR); |
@@ -1463,6 +1423,9 @@ static void asm_min_max(ASMState *as, IRIns *ir, int ismax) | |||
1463 | } | 1423 | } |
1464 | } | 1424 | } |
1465 | 1425 | ||
1426 | #define asm_min(as, ir) asm_min_max(as, ir, 0) | ||
1427 | #define asm_max(as, ir) asm_min_max(as, ir, 1) | ||
1428 | |||
1466 | /* -- Comparisons --------------------------------------------------------- */ | 1429 | /* -- Comparisons --------------------------------------------------------- */ |
1467 | 1430 | ||
1468 | static void asm_comp(ASMState *as, IRIns *ir) | 1431 | static void asm_comp(ASMState *as, IRIns *ir) |
@@ -1500,7 +1463,7 @@ static void asm_comp(ASMState *as, IRIns *ir) | |||
1500 | } | 1463 | } |
1501 | } | 1464 | } |
1502 | 1465 | ||
1503 | static void asm_compeq(ASMState *as, IRIns *ir) | 1466 | static void asm_equal(ASMState *as, IRIns *ir) |
1504 | { | 1467 | { |
1505 | Reg right, left = ra_alloc2(as, ir, irt_isnum(ir->t) ? RSET_FPR : RSET_GPR); | 1468 | Reg right, left = ra_alloc2(as, ir, irt_isnum(ir->t) ? RSET_FPR : RSET_GPR); |
1506 | right = (left >> 8); left &= 255; | 1469 | right = (left >> 8); left &= 255; |
@@ -1574,8 +1537,8 @@ static void asm_hiop(ASMState *as, IRIns *ir) | |||
1574 | } else if ((ir-1)->o == IR_XSTORE) { | 1537 | } else if ((ir-1)->o == IR_XSTORE) { |
1575 | as->curins--; /* Handle both stores here. */ | 1538 | as->curins--; /* Handle both stores here. */ |
1576 | if ((ir-1)->r != RID_SINK) { | 1539 | if ((ir-1)->r != RID_SINK) { |
1577 | asm_xstore(as, ir, LJ_LE ? 4 : 0); | 1540 | asm_xstore_(as, ir, LJ_LE ? 4 : 0); |
1578 | asm_xstore(as, ir-1, LJ_LE ? 0 : 4); | 1541 | asm_xstore_(as, ir-1, LJ_LE ? 0 : 4); |
1579 | } | 1542 | } |
1580 | return; | 1543 | return; |
1581 | } | 1544 | } |
@@ -1771,131 +1734,13 @@ static void asm_tail_prep(ASMState *as) | |||
1771 | as->invmcp = as->loopref ? as->mcp : NULL; | 1734 | as->invmcp = as->loopref ? as->mcp : NULL; |
1772 | } | 1735 | } |
1773 | 1736 | ||
1774 | /* -- Instruction dispatch ------------------------------------------------ */ | ||
1775 | |||
1776 | /* Assemble a single instruction. */ | ||
1777 | static void asm_ir(ASMState *as, IRIns *ir) | ||
1778 | { | ||
1779 | switch ((IROp)ir->o) { | ||
1780 | /* Miscellaneous ops. */ | ||
1781 | case IR_LOOP: asm_loop(as); break; | ||
1782 | case IR_NOP: case IR_XBAR: lua_assert(!ra_used(ir)); break; | ||
1783 | case IR_USE: | ||
1784 | ra_alloc1(as, ir->op1, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); break; | ||
1785 | case IR_PHI: asm_phi(as, ir); break; | ||
1786 | case IR_HIOP: asm_hiop(as, ir); break; | ||
1787 | case IR_GCSTEP: asm_gcstep(as, ir); break; | ||
1788 | |||
1789 | /* Guarded assertions. */ | ||
1790 | case IR_EQ: case IR_NE: asm_compeq(as, ir); break; | ||
1791 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: | ||
1792 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: | ||
1793 | case IR_ABC: | ||
1794 | asm_comp(as, ir); | ||
1795 | break; | ||
1796 | |||
1797 | case IR_RETF: asm_retf(as, ir); break; | ||
1798 | |||
1799 | /* Bit ops. */ | ||
1800 | case IR_BNOT: asm_bitnot(as, ir); break; | ||
1801 | case IR_BSWAP: asm_bitswap(as, ir); break; | ||
1802 | |||
1803 | case IR_BAND: asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI); break; | ||
1804 | case IR_BOR: asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI); break; | ||
1805 | case IR_BXOR: asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI); break; | ||
1806 | |||
1807 | case IR_BSHL: asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL); break; | ||
1808 | case IR_BSHR: asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL); break; | ||
1809 | case IR_BSAR: asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA); break; | ||
1810 | case IR_BROL: lua_assert(0); break; | ||
1811 | case IR_BROR: asm_bitror(as, ir); break; | ||
1812 | |||
1813 | /* Arithmetic ops. */ | ||
1814 | case IR_ADD: asm_add(as, ir); break; | ||
1815 | case IR_SUB: asm_sub(as, ir); break; | ||
1816 | case IR_MUL: asm_mul(as, ir); break; | ||
1817 | case IR_DIV: asm_fparith(as, ir, MIPSI_DIV_D); break; | ||
1818 | case IR_MOD: asm_callid(as, ir, IRCALL_lj_vm_modi); break; | ||
1819 | case IR_POW: asm_callid(as, ir, IRCALL_lj_vm_powi); break; | ||
1820 | case IR_NEG: asm_neg(as, ir); break; | ||
1821 | |||
1822 | case IR_ABS: asm_fpunary(as, ir, MIPSI_ABS_D); break; | ||
1823 | case IR_ATAN2: asm_callid(as, ir, IRCALL_atan2); break; | ||
1824 | case IR_LDEXP: asm_callid(as, ir, IRCALL_ldexp); break; | ||
1825 | case IR_MIN: asm_min_max(as, ir, 0); break; | ||
1826 | case IR_MAX: asm_min_max(as, ir, 1); break; | ||
1827 | case IR_FPMATH: | ||
1828 | if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) | ||
1829 | break; | ||
1830 | if (ir->op2 <= IRFPM_TRUNC) | ||
1831 | asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2); | ||
1832 | else if (ir->op2 == IRFPM_SQRT) | ||
1833 | asm_fpunary(as, ir, MIPSI_SQRT_D); | ||
1834 | else | ||
1835 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); | ||
1836 | break; | ||
1837 | |||
1838 | /* Overflow-checking arithmetic ops. */ | ||
1839 | case IR_ADDOV: asm_arithov(as, ir); break; | ||
1840 | case IR_SUBOV: asm_arithov(as, ir); break; | ||
1841 | case IR_MULOV: asm_mulov(as, ir); break; | ||
1842 | |||
1843 | /* Memory references. */ | ||
1844 | case IR_AREF: asm_aref(as, ir); break; | ||
1845 | case IR_HREF: asm_href(as, ir); break; | ||
1846 | case IR_HREFK: asm_hrefk(as, ir); break; | ||
1847 | case IR_NEWREF: asm_newref(as, ir); break; | ||
1848 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; | ||
1849 | case IR_FREF: asm_fref(as, ir); break; | ||
1850 | case IR_STRREF: asm_strref(as, ir); break; | ||
1851 | |||
1852 | /* Loads and stores. */ | ||
1853 | case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: | ||
1854 | asm_ahuvload(as, ir); | ||
1855 | break; | ||
1856 | case IR_FLOAD: asm_fload(as, ir); break; | ||
1857 | case IR_XLOAD: asm_xload(as, ir); break; | ||
1858 | case IR_SLOAD: asm_sload(as, ir); break; | ||
1859 | |||
1860 | case IR_ASTORE: case IR_HSTORE: case IR_USTORE: asm_ahustore(as, ir); break; | ||
1861 | case IR_FSTORE: asm_fstore(as, ir); break; | ||
1862 | case IR_XSTORE: asm_xstore(as, ir, 0); break; | ||
1863 | |||
1864 | /* Allocations. */ | ||
1865 | case IR_SNEW: case IR_XSNEW: asm_snew(as, ir); break; | ||
1866 | case IR_TNEW: asm_tnew(as, ir); break; | ||
1867 | case IR_TDUP: asm_tdup(as, ir); break; | ||
1868 | case IR_CNEW: case IR_CNEWI: asm_cnew(as, ir); break; | ||
1869 | |||
1870 | /* Write barriers. */ | ||
1871 | case IR_TBAR: asm_tbar(as, ir); break; | ||
1872 | case IR_OBAR: asm_obar(as, ir); break; | ||
1873 | |||
1874 | /* Type conversions. */ | ||
1875 | case IR_CONV: asm_conv(as, ir); break; | ||
1876 | case IR_TOBIT: asm_tobit(as, ir); break; | ||
1877 | case IR_TOSTR: asm_tostr(as, ir); break; | ||
1878 | case IR_STRTO: asm_strto(as, ir); break; | ||
1879 | |||
1880 | /* Calls. */ | ||
1881 | case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break; | ||
1882 | case IR_CALLXS: asm_callx(as, ir); break; | ||
1883 | case IR_CARG: break; | ||
1884 | |||
1885 | default: | ||
1886 | setintV(&as->J->errinfo, ir->o); | ||
1887 | lj_trace_err_info(as->J, LJ_TRERR_NYIIR); | ||
1888 | break; | ||
1889 | } | ||
1890 | } | ||
1891 | |||
1892 | /* -- Trace setup --------------------------------------------------------- */ | 1737 | /* -- Trace setup --------------------------------------------------------- */ |
1893 | 1738 | ||
1894 | /* Ensure there are enough stack slots for call arguments. */ | 1739 | /* Ensure there are enough stack slots for call arguments. */ |
1895 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) | 1740 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) |
1896 | { | 1741 | { |
1897 | IRRef args[CCI_NARGS_MAX*2]; | 1742 | IRRef args[CCI_NARGS_MAX*2]; |
1898 | uint32_t i, nargs = (int)CCI_NARGS(ci); | 1743 | uint32_t i, nargs = CCI_XNARGS(ci); |
1899 | int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; | 1744 | int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; |
1900 | asm_collectargs(as, ir, ci, args); | 1745 | asm_collectargs(as, ir, ci, args); |
1901 | for (i = 0; i < nargs; i++) { | 1746 | for (i = 0; i < nargs; i++) { |