aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMike Pall <mike>2011-02-05 21:50:15 +0100
committerMike Pall <mike>2011-02-05 21:50:15 +0100
commit26fadcd25bb9e84e15be0a81a56806d5419c3183 (patch)
tree91bb326735cb745093d63845027f4bff238b3dc3 /src
parentbf05209e1446aa13416b3dfffe021c85057b9a5d (diff)
downloadluajit-26fadcd25bb9e84e15be0a81a56806d5419c3183.tar.gz
luajit-26fadcd25bb9e84e15be0a81a56806d5419c3183.tar.bz2
luajit-26fadcd25bb9e84e15be0a81a56806d5419c3183.zip
FFI: Record simple C function calls.
Only handles cdecl and fixarg C functions. Doesn't handle pass-by-value aggregates. Doesn't handle 64 bit args/returns on 32 bit CPUs.
Diffstat (limited to 'src')
-rw-r--r--src/lj_asm.c117
-rw-r--r--src/lj_crecord.c71
-rw-r--r--src/lj_ir.h4
-rw-r--r--src/lj_opt_fold.c1
-rw-r--r--src/lj_opt_mem.c7
-rw-r--r--src/lj_traceerr.h1
6 files changed, 169 insertions, 32 deletions
diff --git a/src/lj_asm.c b/src/lj_asm.c
index 77b55f0c..acad3b25 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -1459,7 +1459,6 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
1459/* Generate a call to a C function. */ 1459/* Generate a call to a C function. */
1460static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) 1460static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
1461{ 1461{
1462 RegSet allow = RSET_ALL;
1463 uint32_t n, nargs = CCI_NARGS(ci); 1462 uint32_t n, nargs = CCI_NARGS(ci);
1464 int32_t ofs = STACKARG_OFS; 1463 int32_t ofs = STACKARG_OFS;
1465 uint32_t gprs = REGARG_GPRS; 1464 uint32_t gprs = REGARG_GPRS;
@@ -1467,24 +1466,25 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
1467 Reg fpr = REGARG_FIRSTFPR; 1466 Reg fpr = REGARG_FIRSTFPR;
1468#endif 1467#endif
1469 lua_assert(!(nargs > 2 && (ci->flags&CCI_FASTCALL))); /* Avoid stack adj. */ 1468 lua_assert(!(nargs > 2 && (ci->flags&CCI_FASTCALL))); /* Avoid stack adj. */
1470 emit_call(as, ci->func); 1469 if ((void *)ci->func)
1470 emit_call(as, ci->func);
1471 for (n = 0; n < nargs; n++) { /* Setup args. */ 1471 for (n = 0; n < nargs; n++) { /* Setup args. */
1472 IRRef ref = args[n]; 1472 IRRef ref = args[n];
1473 IRIns *ir = IR(ref); 1473 IRIns *ir = IR(ref);
1474 Reg r; 1474 Reg r;
1475#if LJ_64 && LJ_ABI_WIN 1475#if LJ_64 && LJ_ABI_WIN
1476 /* Windows/x64 argument registers are strictly positional. */ 1476 /* Windows/x64 argument registers are strictly positional. */
1477 r = irt_isnum(ir->t) ? (fpr <= REGARG_LASTFPR ? fpr : 0) : (gprs & 31); 1477 r = irt_isfp(ir->t) ? (fpr <= REGARG_LASTFPR ? fpr : 0) : (gprs & 31);
1478 fpr++; gprs >>= 5; 1478 fpr++; gprs >>= 5;
1479#elif LJ_64 1479#elif LJ_64
1480 /* POSIX/x64 argument registers are used in order of appearance. */ 1480 /* POSIX/x64 argument registers are used in order of appearance. */
1481 if (irt_isnum(ir->t)) { 1481 if (irt_isfp(ir->t)) {
1482 r = fpr <= REGARG_LASTFPR ? fpr : 0; fpr++; 1482 r = fpr <= REGARG_LASTFPR ? fpr : 0; fpr++;
1483 } else { 1483 } else {
1484 r = gprs & 31; gprs >>= 5; 1484 r = gprs & 31; gprs >>= 5;
1485 } 1485 }
1486#else 1486#else
1487 if (irt_isnum(ir->t) || !(ci->flags & CCI_FASTCALL)) { 1487 if (irt_isfp(ir->t) || !(ci->flags & CCI_FASTCALL)) {
1488 r = 0; 1488 r = 0;
1489 } else { 1489 } else {
1490 r = gprs & 31; gprs >>= 5; 1490 r = gprs & 31; gprs >>= 5;
@@ -1514,22 +1514,16 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
1514 emit_movmroi(as, RID_ESP, ofs, (int32_t)ir_knum(ir)->u32.lo); 1514 emit_movmroi(as, RID_ESP, ofs, (int32_t)ir_knum(ir)->u32.lo);
1515 emit_movmroi(as, RID_ESP, ofs+4, (int32_t)ir_knum(ir)->u32.hi); 1515 emit_movmroi(as, RID_ESP, ofs+4, (int32_t)ir_knum(ir)->u32.hi);
1516 } else { 1516 } else {
1517 if ((allow & RSET_FPR) == RSET_EMPTY) 1517 r = ra_alloc1(as, ref, RSET_FPR);
1518 lj_trace_err(as->J, LJ_TRERR_NYICOAL);
1519 r = ra_alloc1(as, ref, allow & RSET_FPR);
1520 allow &= ~RID2RSET(r);
1521 emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto, 1518 emit_rmro(as, irt_isnum(ir->t) ? XO_MOVSDto : XO_MOVSSto,
1522 r, RID_ESP, ofs); 1519 r, RID_ESP, ofs);
1523 } 1520 }
1524 ofs += 8; 1521 ofs += (LJ_32 && irt_isfloat(ir->t)) ? 4 : 8;
1525 } else { /* Non-FP argument is on stack. */ 1522 } else { /* Non-FP argument is on stack. */
1526 if (LJ_32 && ref < ASMREF_TMP1) { 1523 if (LJ_32 && ref < ASMREF_TMP1) {
1527 emit_movmroi(as, RID_ESP, ofs, ir->i); 1524 emit_movmroi(as, RID_ESP, ofs, ir->i);
1528 } else { 1525 } else {
1529 if ((allow & RSET_GPR) == RSET_EMPTY) 1526 r = ra_alloc1(as, ref, RSET_GPR);
1530 lj_trace_err(as->J, LJ_TRERR_NYICOAL);
1531 r = ra_alloc1(as, ref, allow & RSET_GPR);
1532 allow &= ~RID2RSET(r);
1533 emit_movtomro(as, REX_64IR(ir, r), RID_ESP, ofs); 1527 emit_movtomro(as, REX_64IR(ir, r), RID_ESP, ofs);
1534 } 1528 }
1535 ofs += sizeof(intptr_t); 1529 ofs += sizeof(intptr_t);
@@ -1575,7 +1569,8 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci)
1575 emit_movtomro(as, RID_RET, RID_ESP, ofs); 1569 emit_movtomro(as, RID_RET, RID_ESP, ofs);
1576 emit_movtomro(as, RID_RETHI, RID_ESP, ofs+4); 1570 emit_movtomro(as, RID_RETHI, RID_ESP, ofs+4);
1577 } else { 1571 } else {
1578 emit_rmro(as, XO_FSTPq, XOg_FSTPq, RID_ESP, ofs); 1572 emit_rmro(as, irt_isnum(ir->t) ? XO_FSTPq : XO_FSTPd,
1573 irt_isnum(ir->t) ? XOg_FSTPq : XOg_FSTPd, RID_ESP, ofs);
1579 } 1574 }
1580#endif 1575#endif
1581 } else { 1576 } else {
@@ -1585,7 +1580,7 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci)
1585 } 1580 }
1586} 1581}
1587 1582
1588/* Collect arguments from CALL* and ARG instructions. */ 1583/* Collect arguments from CALL* and CARG instructions. */
1589static void asm_collectargs(ASMState *as, IRIns *ir, 1584static void asm_collectargs(ASMState *as, IRIns *ir,
1590 const CCallInfo *ci, IRRef *args) 1585 const CCallInfo *ci, IRRef *args)
1591{ 1586{
@@ -1610,6 +1605,40 @@ static void asm_call(ASMState *as, IRIns *ir)
1610 asm_gencall(as, ci, args); 1605 asm_gencall(as, ci, args);
1611} 1606}
1612 1607
1608/* Reconstruct CCallInfo flags for CALLX*. */
1609static uint32_t asm_callx_flags(ASMState *as, IRIns *ir)
1610{
1611 uint32_t nargs = 0;
1612 if (ir->op1 != REF_NIL) { /* Count number of arguments first. */
1613 IRIns *ira = IR(ir->op1);
1614 nargs++;
1615 while (ira->o == IR_CARG) { nargs++; ira = IR(ira->op1); }
1616 }
1617 /* NYI: fastcall etc. */
1618 return (nargs | (ir->t.irt << CCI_OTSHIFT));
1619}
1620
1621static void asm_callx(ASMState *as, IRIns *ir)
1622{
1623 IRRef args[CCI_NARGS_MAX];
1624 CCallInfo ci;
1625 IRIns *irf;
1626 ci.flags = asm_callx_flags(as, ir);
1627 asm_collectargs(as, ir, &ci, args);
1628 asm_setupresult(as, ir, &ci);
1629 irf = IR(ir->op2);
1630 if (LJ_32 && irref_isk(ir->op2)) { /* Call to constant address on x86. */
1631 ci.func = (ASMFunction)(void *)(uintptr_t)(uint32_t)irf->i;
1632 } else {
1633 /* Prefer a non-argument register or RID_RET for indirect calls. */
1634 RegSet allow = (RSET_GPR & ~RSET_SCRATCH)|RID2RSET(RID_RET);
1635 Reg r = ra_alloc1(as, ir->op2, allow);
1636 emit_rr(as, XO_GROUP5, XOg_CALL, r);
1637 ci.func = (ASMFunction)(void *)0;
1638 }
1639 asm_gencall(as, &ci, args);
1640}
1641
1613/* -- Returns ------------------------------------------------------------- */ 1642/* -- Returns ------------------------------------------------------------- */
1614 1643
1615/* Return to lower frame. Guard that it goes to the right spot. */ 1644/* Return to lower frame. Guard that it goes to the right spot. */
@@ -4086,6 +4115,7 @@ static void asm_ir(ASMState *as, IRIns *ir)
4086 4115
4087 /* Calls. */ 4116 /* Calls. */
4088 case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break; 4117 case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break;
4118 case IR_CALLXS: asm_callx(as, ir); break;
4089 case IR_CARG: break; 4119 case IR_CARG: break;
4090 4120
4091 default: 4121 default:
@@ -4113,6 +4143,43 @@ static void asm_trace(ASMState *as)
4113 4143
4114/* -- Trace setup --------------------------------------------------------- */ 4144/* -- Trace setup --------------------------------------------------------- */
4115 4145
4146/* Ensure there are enough stack slots for call arguments. */
4147static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
4148{
4149 IRRef args[CCI_NARGS_MAX];
4150 uint32_t nargs = (int)CCI_NARGS(ci);
4151 int nslots = 0;
4152 asm_collectargs(as, ir, ci, args);
4153#if LJ_64
4154 if (LJ_ABI_WIN) {
4155 nslots = (int)(nargs*2); /* Only matters for more than four args. */
4156 } else {
4157 uint32_t i;
4158 int ngpr = 6, nfpr = 8;
4159 for (i = 0; i < nargs; i++)
4160 if (irt_isfp(IR(args[i])->t)) {
4161 if (nfpr > 0) nfpr--; else nslots += 2;
4162 } else {
4163 if (ngpr > 0) ngpr--; else nslots += 2;
4164 }
4165 }
4166 if (nslots > as->evenspill) /* Leave room for args in stack slots. */
4167 as->evenspill = nslots;
4168 return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET);
4169#else
4170 if ((ci->flags & CCI_FASTCALL)) {
4171 lua_assert(nargs <= 2);
4172 } else {
4173 uint32_t i;
4174 for (i = 0; i < nargs; i++)
4175 nslots += irt_isnum(IR(args[i])->t) ? 2 : 1;
4176 if (nslots > as->evenspill) /* Leave room for args. */
4177 as->evenspill = nslots;
4178 }
4179 return irt_isfp(ir->t) ? REGSP_INIT : REGSP_HINT(RID_RET);
4180#endif
4181}
4182
4116/* Clear reg/sp for all instructions and add register hints. */ 4183/* Clear reg/sp for all instructions and add register hints. */
4117static void asm_setup_regsp(ASMState *as, GCtrace *T) 4184static void asm_setup_regsp(ASMState *as, GCtrace *T)
4118{ 4185{
@@ -4161,17 +4228,17 @@ static void asm_setup_regsp(ASMState *as, GCtrace *T)
4161 } 4228 }
4162 } 4229 }
4163 break; 4230 break;
4231 case IR_CALLXS: {
4232 CCallInfo ci;
4233 ci.flags = asm_callx_flags(as, ir);
4234 ir->prev = asm_setup_call_slots(as, ir, &ci);
4235 if (inloop)
4236 as->modset |= RSET_SCRATCH;
4237 continue;
4238 }
4164 case IR_CALLN: case IR_CALLL: case IR_CALLS: { 4239 case IR_CALLN: case IR_CALLL: case IR_CALLS: {
4165 const CCallInfo *ci = &lj_ir_callinfo[ir->op2]; 4240 const CCallInfo *ci = &lj_ir_callinfo[ir->op2];
4166#if LJ_64 4241 ir->prev = asm_setup_call_slots(as, ir, ci);
4167 lua_assert(CCI_NARGS(ci) <= (LJ_ABI_WIN ? 4 : 6));
4168 ir->prev = REGSP_HINT(irt_isnum(ir->t) ? RID_FPRET : RID_RET);
4169#else
4170 lua_assert(!(ci->flags & CCI_FASTCALL) || CCI_NARGS(ci) <= 2);
4171 if (CCI_NARGS(ci) > (uint32_t)as->evenspill) /* Leave room for args. */
4172 as->evenspill = (int32_t)CCI_NARGS(ci);
4173 ir->prev = REGSP_HINT(RID_RET);
4174#endif
4175 if (inloop) 4242 if (inloop)
4176 as->modset |= (ci->flags & CCI_NOFPRCLOBBER) ? 4243 as->modset |= (ci->flags & CCI_NOFPRCLOBBER) ?
4177 (RSET_SCRATCH & ~RSET_FPR) : RSET_SCRATCH; 4244 (RSET_SCRATCH & ~RSET_FPR) : RSET_SCRATCH;
diff --git a/src/lj_crecord.c b/src/lj_crecord.c
index b4bfd0c2..2ecd2867 100644
--- a/src/lj_crecord.c
+++ b/src/lj_crecord.c
@@ -670,14 +670,79 @@ static void crec_alloc(jit_State *J, RecordFFData *rd, CTypeID id)
670 } 670 }
671} 671}
672 672
673/* Record argument conversions. */
674static TRef crec_call_args(jit_State *J, RecordFFData *rd,
675 CTState *cts, CType *ct)
676{
677 TRef args[CCI_NARGS_MAX];
678 MSize i, n;
679 TRef tr;
680 args[0] = TREF_NIL;
681 for (n = 0; J->base[n+1]; n++) {
682 CType *d;
683 do {
684 if (!ct->sib)
685 lj_trace_err(J, LJ_TRERR_NYICALL);
686 ct = ctype_get(cts, ct->sib);
687 } while (ctype_isattrib(ct->info));
688 if (!ctype_isfield(ct->info))
689 lj_trace_err(J, LJ_TRERR_NYICALL);
690 d = ctype_rawchild(cts, ct);
691 if (ctype_isenum(d->info)) d = ctype_child(cts, d);
692 if (!(ctype_isnum(d->info) || ctype_isptr(d->info)))
693 lj_trace_err(J, LJ_TRERR_NYICALL);
694 args[n] = crec_ct_tv(J, d, 0, J->base[n+1], &rd->argv[n+1]);
695 }
696 tr = args[0];
697 for (i = 1; i < n; i++)
698 tr = emitir(IRT(IR_CARG, IRT_NIL), tr, args[i]);
699 return tr;
700}
701
702/* Record function call. */
703static int crec_call(jit_State *J, RecordFFData *rd, GCcdata *cd)
704{
705 CTState *cts = ctype_ctsG(J2G(J));
706 CType *ct = ctype_raw(cts, cd->typeid);
707 IRType tp = IRT_PTR;
708 if (ctype_isptr(ct->info)) {
709 tp = (LJ_64 && ct->size == 8) ? IRT_P64 : IRT_P32;
710 ct = ctype_rawchild(cts, ct);
711 }
712 if (ctype_isfunc(ct->info)) {
713 TRef func = emitir(IRT(IR_FLOAD, tp), J->base[0], IRFL_CDATA_PTR);
714 CType *ctr = ctype_rawchild(cts, ct);
715 IRType t = crec_ct2irt(ctr);
716 TRef tr;
717 if (ctype_isenum(ctr->info)) ctr = ctype_child(cts, ctr);
718 if (!(ctype_isnum(ctr->info) || ctype_isptr(ctr->info)) ||
719 ctype_isbool(ctr->info) || (ct->info & CTF_VARARG) ||
720#if LJ_TARGET_X86
721 ctype_cconv(ct->info) != CTCC_CDECL ||
722#endif
723 t == IRT_CDATA || (LJ_32 && (t == IRT_I64 || t == IRT_U64)))
724 lj_trace_err(J, LJ_TRERR_NYICALL);
725 tr = emitir(IRT(IR_CALLXS, t), crec_call_args(J, rd, cts, ct), func);
726 if (t == IRT_FLOAT || t == IRT_U32) {
727 tr = emitconv(tr, IRT_NUM, t, 0);
728 } else if (t == IRT_PTR || (LJ_64 && t == IRT_P32) ||
729 (LJ_64 && (t == IRT_I64 || t == IRT_U64))) {
730 TRef trid = lj_ir_kint(J, ctype_cid(ct->info));
731 tr = emitir(IRTG(IR_CNEWI, IRT_CDATA), trid, tr);
732 }
733 J->base[0] = tr;
734 return 1;
735 }
736 return 0;
737}
738
673void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd) 739void LJ_FASTCALL recff_cdata_call(jit_State *J, RecordFFData *rd)
674{ 740{
675 GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]); 741 GCcdata *cd = argv2cdata(J, J->base[0], &rd->argv[0]);
676 if (cd->typeid == CTID_CTYPEID) { 742 if (cd->typeid == CTID_CTYPEID)
677 crec_alloc(J, rd, crec_constructor(J, cd, J->base[0])); 743 crec_alloc(J, rd, crec_constructor(J, cd, J->base[0]));
678 } else { 744 else if (!crec_call(J, rd, cd))
679 lj_trace_err(J, LJ_TRERR_BADTYPE); 745 lj_trace_err(J, LJ_TRERR_BADTYPE);
680 }
681} 746}
682 747
683static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm) 748static TRef crec_arith_int64(jit_State *J, TRef *sp, CType **s, MMS mm)
diff --git a/src/lj_ir.h b/src/lj_ir.h
index bedb4c2b..532d7a9e 100644
--- a/src/lj_ir.h
+++ b/src/lj_ir.h
@@ -129,6 +129,7 @@
129 _(CALLN, N , ref, lit) \ 129 _(CALLN, N , ref, lit) \
130 _(CALLL, L , ref, lit) \ 130 _(CALLL, L , ref, lit) \
131 _(CALLS, S , ref, lit) \ 131 _(CALLS, S , ref, lit) \
132 _(CALLXS, S , ref, ref) \
132 _(CARG, N , ref, ref) \ 133 _(CARG, N , ref, ref) \
133 \ 134 \
134 /* End of list. */ 135 /* End of list. */
@@ -236,7 +237,7 @@ typedef struct CCallInfo {
236} CCallInfo; 237} CCallInfo;
237 238
238#define CCI_NARGS(ci) ((ci)->flags & 0xff) /* Extract # of args. */ 239#define CCI_NARGS(ci) ((ci)->flags & 0xff) /* Extract # of args. */
239#define CCI_NARGS_MAX 16 /* Max. # of args. */ 240#define CCI_NARGS_MAX 32 /* Max. # of args. */
240 241
241#define CCI_OTSHIFT 16 242#define CCI_OTSHIFT 16
242#define CCI_OPTYPE(ci) ((ci)->flags >> CCI_OTSHIFT) /* Get op/type. */ 243#define CCI_OPTYPE(ci) ((ci)->flags >> CCI_OTSHIFT) /* Get op/type. */
@@ -590,7 +591,6 @@ typedef union IRIns {
590 check_exp((ir)->o == IR_KNUM || (ir)->o == IR_KINT64, mref((ir)->ptr,cTValue)) 591 check_exp((ir)->o == IR_KNUM || (ir)->o == IR_KINT64, mref((ir)->ptr,cTValue))
591#define ir_kptr(ir) \ 592#define ir_kptr(ir) \
592 check_exp((ir)->o == IR_KPTR || (ir)->o == IR_KKPTR, mref((ir)->ptr, void)) 593 check_exp((ir)->o == IR_KPTR || (ir)->o == IR_KKPTR, mref((ir)->ptr, void))
593
594LJ_STATIC_ASSERT((int)IRT_GUARD == (int)IRM_W); 594LJ_STATIC_ASSERT((int)IRT_GUARD == (int)IRM_W);
595 595
596/* A store or any other op with a non-weak guard has a side-effect. */ 596/* A store or any other op with a non-weak guard has a side-effect. */
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c
index ef397aea..1172f4fc 100644
--- a/src/lj_opt_fold.c
+++ b/src/lj_opt_fold.c
@@ -1891,6 +1891,7 @@ LJFOLDX(lj_opt_dse_xstore)
1891LJFOLD(NEWREF any any) /* Treated like a store. */ 1891LJFOLD(NEWREF any any) /* Treated like a store. */
1892LJFOLD(CALLS any any) 1892LJFOLD(CALLS any any)
1893LJFOLD(CALLL any any) /* Safeguard fallback. */ 1893LJFOLD(CALLL any any) /* Safeguard fallback. */
1894LJFOLD(CALLXS any any)
1894LJFOLD(RETF any any) /* Modifies BASE. */ 1895LJFOLD(RETF any any) /* Modifies BASE. */
1895LJFOLD(TNEW any any) 1896LJFOLD(TNEW any any)
1896LJFOLD(TDUP any) 1897LJFOLD(TDUP any)
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c
index cad85bb7..211c329a 100644
--- a/src/lj_opt_mem.c
+++ b/src/lj_opt_mem.c
@@ -675,7 +675,8 @@ TRef LJ_FASTCALL lj_opt_fwd_xload(jit_State *J)
675 /* Search for conflicting stores. */ 675 /* Search for conflicting stores. */
676 ref = J->chain[IR_XSTORE]; 676 ref = J->chain[IR_XSTORE];
677retry: 677retry:
678 while (ref > xref) { 678 if (J->chain[IR_CALLXS] > lim) lim = J->chain[IR_CALLXS];
679 while (ref > lim) {
679 IRIns *store = IR(ref); 680 IRIns *store = IR(ref);
680 switch (aa_xref(J, xr, fins, store)) { 681 switch (aa_xref(J, xr, fins, store)) {
681 case ALIAS_NO: break; /* Continue searching. */ 682 case ALIAS_NO: break; /* Continue searching. */
@@ -732,10 +733,12 @@ TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J)
732{ 733{
733 IRRef xref = fins->op1; 734 IRRef xref = fins->op1;
734 IRIns *xr = IR(xref); 735 IRIns *xr = IR(xref);
736 IRRef lim = xref; /* Search limit. */
735 IRRef val = fins->op2; /* Stored value reference. */ 737 IRRef val = fins->op2; /* Stored value reference. */
736 IRRef1 *refp = &J->chain[IR_XSTORE]; 738 IRRef1 *refp = &J->chain[IR_XSTORE];
737 IRRef ref = *refp; 739 IRRef ref = *refp;
738 while (ref > xref) { /* Search for redundant or conflicting stores. */ 740 if (J->chain[IR_CALLXS] > lim) lim = J->chain[IR_CALLXS];
741 while (ref > lim) { /* Search for redundant or conflicting stores. */
739 IRIns *store = IR(ref); 742 IRIns *store = IR(ref);
740 switch (aa_xref(J, xr, fins, store)) { 743 switch (aa_xref(J, xr, fins, store)) {
741 case ALIAS_NO: 744 case ALIAS_NO:
diff --git a/src/lj_traceerr.h b/src/lj_traceerr.h
index f0c45963..756330ec 100644
--- a/src/lj_traceerr.h
+++ b/src/lj_traceerr.h
@@ -37,6 +37,7 @@ TREDEF(NYITMIX, "NYI: mixed sparse/dense table")
37/* Recording C data operations. */ 37/* Recording C data operations. */
38TREDEF(NOCACHE, "symbol not in cache") 38TREDEF(NOCACHE, "symbol not in cache")
39TREDEF(NYICONV, "NYI: unsupported C type conversion") 39TREDEF(NYICONV, "NYI: unsupported C type conversion")
40TREDEF(NYICALL, "NYI: unsupported C function type")
40 41
41/* Optimizations. */ 42/* Optimizations. */
42TREDEF(GFAIL, "guard would always fail") 43TREDEF(GFAIL, "guard would always fail")