aboutsummaryrefslogtreecommitdiff
path: root/src/lj_asm_x86.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/lj_asm_x86.h')
-rw-r--r--src/lj_asm_x86.h140
1 files changed, 104 insertions, 36 deletions
diff --git a/src/lj_asm_x86.h b/src/lj_asm_x86.h
index 154ca890..391e2de9 100644
--- a/src/lj_asm_x86.h
+++ b/src/lj_asm_x86.h
@@ -369,18 +369,76 @@ static Reg asm_fuseload(ASMState *as, IRRef ref, RegSet allow)
369 369
370/* -- Calls --------------------------------------------------------------- */ 370/* -- Calls --------------------------------------------------------------- */
371 371
372/* Count the required number of stack slots for a call. */
373static int asm_count_call_slots(ASMState *as, const CCallInfo *ci, IRRef *args)
374{
375 uint32_t i, nargs = CCI_NARGS(ci);
376 int nslots = 0;
377#if LJ_64
378 if (LJ_ABI_WIN) {
379 nslots = (int)(nargs*2); /* Only matters for more than four args. */
380 } else {
381 int ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR;
382 for (i = 0; i < nargs; i++)
383 if (args[i] && irt_isfp(IR(args[i])->t)) {
384 if (nfpr > 0) nfpr--; else nslots += 2;
385 } else {
386 if (ngpr > 0) ngpr--; else nslots += 2;
387 }
388 }
389#else
390 int ngpr = 0;
391 if ((ci->flags & CCI_CC_MASK) == CCI_CC_FASTCALL)
392 ngpr = 2;
393 else if ((ci->flags & CCI_CC_MASK) == CCI_CC_THISCALL)
394 ngpr = 1;
395 for (i = 0; i < nargs; i++)
396 if (args[i] && irt_isfp(IR(args[i])->t)) {
397 nslots += irt_isnum(IR(args[i])->t) ? 2 : 1;
398 } else {
399 if (ngpr > 0) ngpr--; else nslots++;
400 }
401#endif
402 return nslots;
403}
404
372/* Generate a call to a C function. */ 405/* Generate a call to a C function. */
373static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) 406static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
374{ 407{
375 uint32_t n, nargs = CCI_NARGS(ci); 408 uint32_t n, nargs = CCI_NARGS(ci);
376 int32_t ofs = STACKARG_OFS; 409 int32_t ofs = STACKARG_OFS;
377 uint32_t gprs = REGARG_GPRS;
378#if LJ_64 410#if LJ_64
411 uint32_t gprs = REGARG_GPRS;
379 Reg fpr = REGARG_FIRSTFPR; 412 Reg fpr = REGARG_FIRSTFPR;
413#if !LJ_ABI_WIN
414 MCode *patchnfpr = NULL;
415#endif
416#else
417 uint32_t gprs = 0;
418 if ((ci->flags & CCI_CC_MASK) != CCI_CC_CDECL) {
419 if ((ci->flags & CCI_CC_MASK) == CCI_CC_THISCALL)
420 gprs = (REGARG_GPRS & 31);
421 else if ((ci->flags & CCI_CC_MASK) == CCI_CC_FASTCALL)
422 gprs = REGARG_GPRS;
423 }
380#endif 424#endif
381 lua_assert(!(nargs > 2 && (ci->flags&CCI_FASTCALL))); /* Avoid stack adj. */
382 if ((void *)ci->func) 425 if ((void *)ci->func)
383 emit_call(as, ci->func); 426 emit_call(as, ci->func);
427#if LJ_64
428 if ((ci->flags & CCI_VARARG)) { /* Special handling for vararg calls. */
429#if LJ_ABI_WIN
430 for (n = 0; n < 4 && n < nargs; n++) {
431 IRIns *ir = IR(args[n]);
432 if (irt_isfp(ir->t)) /* Duplicate FPRs in GPRs. */
433 emit_rr(as, XO_MOVDto, (irt_isnum(ir->t) ? REX_64 : 0) | (fpr+n),
434 ((gprs >> (n*5)) & 31)); /* Either MOVD or MOVQ. */
435 }
436#else
437 patchnfpr = --as->mcp; /* Indicate number of used FPRs in register al. */
438 *--as->mcp = XI_MOVrib | RID_EAX;
439#endif
440 }
441#endif
384 for (n = 0; n < nargs; n++) { /* Setup args. */ 442 for (n = 0; n < nargs; n++) { /* Setup args. */
385 IRRef ref = args[n]; 443 IRRef ref = args[n];
386 IRIns *ir = IR(ref); 444 IRIns *ir = IR(ref);
@@ -392,15 +450,16 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
392#elif LJ_64 450#elif LJ_64
393 /* POSIX/x64 argument registers are used in order of appearance. */ 451 /* POSIX/x64 argument registers are used in order of appearance. */
394 if (irt_isfp(ir->t)) { 452 if (irt_isfp(ir->t)) {
395 r = fpr <= REGARG_LASTFPR ? fpr : 0; fpr++; 453 r = fpr <= REGARG_LASTFPR ? fpr++ : 0;
396 } else { 454 } else {
397 r = gprs & 31; gprs >>= 5; 455 r = gprs & 31; gprs >>= 5;
398 } 456 }
399#else 457#else
400 if (irt_isfp(ir->t) || !(ci->flags & CCI_FASTCALL)) { 458 if (ref && irt_isfp(ir->t)) {
401 r = 0; 459 r = 0;
402 } else { 460 } else {
403 r = gprs & 31; gprs >>= 5; 461 r = gprs & 31; gprs >>= 5;
462 if (!ref) continue;
404 } 463 }
405#endif 464#endif
406 if (r) { /* Argument is in a register. */ 465 if (r) { /* Argument is in a register. */
@@ -442,6 +501,9 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
442 ofs += sizeof(intptr_t); 501 ofs += sizeof(intptr_t);
443 } 502 }
444 } 503 }
504#if LJ_64 && !LJ_ABI_WIN
505 if (patchnfpr) *patchnfpr = fpr - REGARG_FIRSTFPR;
506#endif
445} 507}
446 508
447/* Setup result reg/sp for call. Evict scratch regs. */ 509/* Setup result reg/sp for call. Evict scratch regs. */
@@ -503,23 +565,50 @@ static void asm_call(ASMState *as, IRIns *ir)
503 asm_gencall(as, ci, args); 565 asm_gencall(as, ci, args);
504} 566}
505 567
568/* Return a constant function pointer or NULL for indirect calls. */
569static void *asm_callx_func(ASMState *as, IRIns *irf, IRRef func)
570{
571#if LJ_32
572 UNUSED(as);
573 if (irref_isk(func))
574 return (void *)irf->i;
575#else
576 if (irref_isk(func)) {
577 MCode *p;
578 if (irf->o == IR_KINT64)
579 p = (MCode *)(void *)ir_k64(irf)->u64;
580 else
581 p = (MCode *)(void *)(uintptr_t)(uint32_t)irf->i;
582 if (p - as->mcp == (int32_t)(p - as->mcp))
583 return p; /* Call target is still in +-2GB range. */
584 /* Avoid the indirect case of emit_call(). Try to hoist func addr. */
585 }
586#endif
587 return NULL;
588}
589
506static void asm_callx(ASMState *as, IRIns *ir) 590static void asm_callx(ASMState *as, IRIns *ir)
507{ 591{
508 IRRef args[CCI_NARGS_MAX]; 592 IRRef args[CCI_NARGS_MAX];
509 CCallInfo ci; 593 CCallInfo ci;
594 IRRef func;
510 IRIns *irf; 595 IRIns *irf;
511 ci.flags = asm_callx_flags(as, ir); 596 ci.flags = asm_callx_flags(as, ir);
512 asm_collectargs(as, ir, &ci, args); 597 asm_collectargs(as, ir, &ci, args);
513 asm_setupresult(as, ir, &ci); 598 asm_setupresult(as, ir, &ci);
514 irf = IR(ir->op2); 599#if LJ_32
515 if (LJ_32 && irref_isk(ir->op2)) { /* Call to constant address on x86. */ 600 /* Have to readjust stack after non-cdecl calls due to callee cleanup. */
516 ci.func = (ASMFunction)(void *)(uintptr_t)(uint32_t)irf->i; 601 if ((ci.flags & CCI_CC_MASK) != CCI_CC_CDECL)
517 } else { 602 emit_spsub(as, 4 * asm_count_call_slots(as, &ci, args));
518 /* Prefer a non-argument register or RID_RET for indirect calls. */ 603#endif
519 RegSet allow = (RSET_GPR & ~RSET_SCRATCH)|RID2RSET(RID_RET); 604 func = ir->op2; irf = IR(func);
520 Reg r = ra_alloc1(as, ir->op2, allow); 605 if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); }
606 ci.func = (ASMFunction)asm_callx_func(as, irf, func);
607 if (!(void *)ci.func) {
608 /* Use a (hoistable) non-scratch register for indirect calls. */
609 RegSet allow = (RSET_GPR & ~RSET_SCRATCH);
610 Reg r = ra_alloc1(as, func, allow);
521 emit_rr(as, XO_GROUP5, XOg_CALL, r); 611 emit_rr(as, XO_GROUP5, XOg_CALL, r);
522 ci.func = (ASMFunction)(void *)0;
523 } 612 }
524 asm_gencall(as, &ci, args); 613 asm_gencall(as, &ci, args);
525} 614}
@@ -2608,35 +2697,14 @@ static void asm_ir(ASMState *as, IRIns *ir)
2608static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) 2697static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
2609{ 2698{
2610 IRRef args[CCI_NARGS_MAX]; 2699 IRRef args[CCI_NARGS_MAX];
2611 uint32_t nargs = (int)CCI_NARGS(ci); 2700 int nslots;
2612 int nslots = 0;
2613 asm_collectargs(as, ir, ci, args); 2701 asm_collectargs(as, ir, ci, args);
2614#if LJ_64 2702 nslots = asm_count_call_slots(as, ci, args);
2615 if (LJ_ABI_WIN) {
2616 nslots = (int)(nargs*2); /* Only matters for more than four args. */
2617 } else {
2618 uint32_t i;
2619 int ngpr = 6, nfpr = 8;
2620 for (i = 0; i < nargs; i++)
2621 if (args[i] && irt_isfp(IR(args[i])->t)) {
2622 if (nfpr > 0) nfpr--; else nslots += 2;
2623 } else {
2624 if (ngpr > 0) ngpr--; else nslots += 2;
2625 }
2626 }
2627 if (nslots > as->evenspill) /* Leave room for args in stack slots. */ 2703 if (nslots > as->evenspill) /* Leave room for args in stack slots. */
2628 as->evenspill = nslots; 2704 as->evenspill = nslots;
2705#if LJ_64
2629 return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET); 2706 return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET);
2630#else 2707#else
2631 if ((ci->flags & CCI_FASTCALL)) {
2632 lua_assert(nargs <= 2);
2633 } else {
2634 uint32_t i;
2635 for (i = 0; i < nargs; i++)
2636 nslots += (args[i] && irt_isnum(IR(args[i])->t)) ? 2 : 1;
2637 if (nslots > as->evenspill) /* Leave room for args. */
2638 as->evenspill = nslots;
2639 }
2640 return irt_isfp(ir->t) ? REGSP_INIT : REGSP_HINT(RID_RET); 2708 return irt_isfp(ir->t) ? REGSP_INIT : REGSP_HINT(RID_RET);
2641#endif 2709#endif
2642} 2710}