diff options
Diffstat (limited to 'src/lj_asm.c')
-rw-r--r-- | src/lj_asm.c | 117 |
1 files changed, 92 insertions, 25 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. */ |
1460 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | 1460 | static 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. */ |
1589 | static void asm_collectargs(ASMState *as, IRIns *ir, | 1584 | static 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*. */ | ||
1609 | static 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 | |||
1621 | static 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. */ | ||
4147 | static 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. */ |
4117 | static void asm_setup_regsp(ASMState *as, GCtrace *T) | 4184 | static 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; |