Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 652f1f0

Browse files
Merge pull request #6038 from BruceForstall/PinvokeFeedbackCleanup
Address P/Invoke inlining code review feedback and cleanup
2 parents e0a0ee5 + d415a00 commit 652f1f0

File tree

8 files changed

+163
-95
lines changed

8 files changed

+163
-95
lines changed

src/jit/codegencommon.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -686,12 +686,8 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
686686
case CORINFO_HELP_STOP_FOR_GC:
687687
return RBM_STOP_FOR_GC_TRASH;
688688

689-
#ifdef _TARGET_X86_
690689
case CORINFO_HELP_INIT_PINVOKE_FRAME:
691-
// On x86, this helper has a custom calling convention that takes EDI as argument
692-
// (but doesn't trash it), trashes EAX, and returns ESI.
693-
return RBM_PINVOKE_SCRATCH | RBM_PINVOKE_TCB;
694-
#endif // _TARGET_X86_
690+
return RBM_INIT_PINVOKE_FRAME_TRASH;
695691

696692
default:
697693
return RBM_CALLEE_TRASH;

src/jit/codegenxarch.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6064,7 +6064,7 @@ void CodeGen::genCallInstruction(GenTreePtr node)
60646064
else
60656065
{
60666066
#ifdef _TARGET_X86_
6067-
if ((call->gtCallType == CT_HELPER) && (call->gtCallMethHnd == compiler->eeFindHelper(CORINFO_HELP_INIT_PINVOKE_FRAME)))
6067+
if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
60686068
{
60696069
// The x86 CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
60706070
// TCB in REG_PINVOKE_TCB. AMD64/ARM64 use the standard calling convention. fgMorphCall() sets the

src/jit/gentree.cpp

Lines changed: 84 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,71 @@ GenTreeCall::GetOtherRegMask() const
13491349
return resultMask;
13501350
}
13511351

1352+
#ifndef LEGACY_BACKEND
1353+
1354+
//-------------------------------------------------------------------------
1355+
// HasNonStandardAddedArgs: Return true if the method has non-standard args added to the call
1356+
// argument list during argument morphing (fgMorphArgs), e.g., passed in R10 or R11 on AMD64.
1357+
// See also GetNonStandardAddedArgCount().
1358+
//
1359+
// Arguments:
1360+
// compiler - the compiler instance
1361+
//
1362+
// Return Value:
1363+
// true if there are any such args, false otherwise.
1364+
//
1365+
bool GenTreeCall::HasNonStandardAddedArgs(Compiler* compiler) const
1366+
{
1367+
return GetNonStandardAddedArgCount(compiler) != 0;
1368+
}
1369+
1370+
1371+
//-------------------------------------------------------------------------
1372+
// GetNonStandardAddedArgCount: Get the count of non-standard arguments that have been added
1373+
// during call argument morphing (fgMorphArgs). Do not count non-standard args that are already
1374+
// counted in the argument list prior to morphing.
1375+
//
1376+
// This function is used to help map the caller and callee arguments during tail call setup.
1377+
//
1378+
// Arguments:
1379+
// compiler - the compiler instance
1380+
//
1381+
// Return Value:
1382+
// The count of args, as described.
1383+
//
1384+
// Notes:
1385+
// It would be more general to have fgMorphArgs set a bit on the call node when such
1386+
// args are added to a call, and a bit on each such arg, and then have this code loop
1387+
// over the call args when the special call bit is set, counting the args with the special
1388+
// arg bit. This seems pretty heavyweight, though. Instead, this logic needs to be kept
1389+
// in sync with fgMorphArgs.
1390+
//
1391+
int GenTreeCall::GetNonStandardAddedArgCount(Compiler* compiler) const
1392+
{
1393+
if (IsUnmanaged() && !compiler->opts.ShouldUsePInvokeHelpers())
1394+
{
1395+
// R11 = PInvoke cookie param
1396+
return 1;
1397+
}
1398+
else if (gtCallType == CT_INDIRECT)
1399+
{
1400+
if (IsVirtualStub())
1401+
{
1402+
// R11 = Virtual stub param
1403+
return 1;
1404+
}
1405+
else if (gtCallCookie != nullptr)
1406+
{
1407+
// R10 = PInvoke target param
1408+
// R11 = PInvoke cookie param
1409+
return 2;
1410+
}
1411+
}
1412+
return 0;
1413+
}
1414+
1415+
#endif // !LEGACY_BACKEND
1416+
13521417
//-------------------------------------------------------------------------
13531418
// TreatAsHasRetBufArg:
13541419
//
@@ -1370,7 +1435,7 @@ GenTreeCall::GetOtherRegMask() const
13701435
// aren't actually defined to return a struct, so they don't expect
13711436
// their RetBuf to be passed in x8, instead they expect it in x0.
13721437
//
1373-
bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler)
1438+
bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler) const
13741439
{
13751440
if (HasRetBufArg())
13761441
{
@@ -1381,12 +1446,12 @@ bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler)
13811446
// If we see a Jit helper call that returns a TYP_STRUCT we will
13821447
// transform it as if it has a Return Buffer Argument
13831448
//
1384-
if (IsHelperCall() && (gtCall.gtReturnType == TYP_STRUCT))
1449+
if (IsHelperCall() && (gtReturnType == TYP_STRUCT))
13851450
{
13861451
// There are two possible helper calls that use this path:
13871452
// CORINFO_HELP_GETFIELDSTRUCT and CORINFO_HELP_UNBOX_NULLABLE
13881453
//
1389-
CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCall.gtCallMethHnd);
1454+
CorInfoHelpFunc helpFunc = compiler->eeGetHelperNum(gtCallMethHnd);
13901455

13911456
if (helpFunc == CORINFO_HELP_GETFIELDSTRUCT)
13921457
{
@@ -1404,6 +1469,22 @@ bool GenTreeCall::TreatAsHasRetBufArg(Compiler* compiler)
14041469
}
14051470
return false;
14061471
}
1472+
1473+
1474+
//-------------------------------------------------------------------------
1475+
// IsHelperCall: Determine if this GT_CALL node is a specific helper call.
1476+
//
1477+
// Arguments:
1478+
// compiler - the compiler instance so that we can call eeFindHelper
1479+
//
1480+
// Return Value:
1481+
// Returns true if this GT_CALL node is a call to the specified helper.
1482+
//
1483+
bool GenTreeCall::IsHelperCall(Compiler* compiler, unsigned helper) const
1484+
{
1485+
return IsHelperCall(compiler->eeFindHelper(helper));
1486+
}
1487+
14071488

14081489
/*****************************************************************************
14091490
*

src/jit/gentree.h

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -2767,44 +2767,17 @@ struct GenTreeCall final : public GenTree
27672767

27682768
#define GTF_CALL_M_R2R_REL_INDIRECT 0x2000 // GT_CALL -- ready to run call is indirected through a relative address
27692769

2770-
bool IsUnmanaged() { return (gtFlags & GTF_CALL_UNMANAGED) != 0; }
2771-
bool NeedsNullCheck() { return (gtFlags & GTF_CALL_NULLCHECK) != 0; }
2772-
bool CallerPop() { return (gtFlags & GTF_CALL_POP_ARGS) != 0; }
2773-
bool IsVirtual() { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) != GTF_CALL_NONVIRT; }
2774-
bool IsVirtualStub() { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB; }
2775-
bool IsVirtualVtable() { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_VTABLE; }
2776-
bool IsInlineCandidate() { return (gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0; }
2770+
bool IsUnmanaged() const { return (gtFlags & GTF_CALL_UNMANAGED) != 0; }
2771+
bool NeedsNullCheck() const { return (gtFlags & GTF_CALL_NULLCHECK) != 0; }
2772+
bool CallerPop() const { return (gtFlags & GTF_CALL_POP_ARGS) != 0; }
2773+
bool IsVirtual() const { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) != GTF_CALL_NONVIRT; }
2774+
bool IsVirtualStub() const { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB; }
2775+
bool IsVirtualVtable() const { return (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_VTABLE; }
2776+
bool IsInlineCandidate() const { return (gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0; }
27772777

27782778
#ifndef LEGACY_BACKEND
2779-
// Whether the method has non-standard args (i.e. passed in R10 or R11)
2780-
// See fgMorphArgs() to know the call types for which non-standard args are inserted.
2781-
bool HasNonStandardArgs() { return IsUnmanaged() || (gtCallType == CT_INDIRECT && (IsVirtualStub() || gtCallCookie)); }
2782-
2783-
// Get the count of non-standard arg count
2784-
int GetNonStandardArgCount()
2785-
{
2786-
if (IsUnmanaged())
2787-
{
2788-
// R11 = PInvoke cookie param
2789-
return 1;
2790-
}
2791-
else if (gtCallType == CT_INDIRECT)
2792-
{
2793-
if (IsVirtualStub())
2794-
{
2795-
// R11 = Virtual stub param
2796-
return 1;
2797-
}
2798-
else if (gtCallCookie != nullptr)
2799-
{
2800-
// R10 = PInvoke target param
2801-
// R11 = PInvoke cookie param
2802-
return 2;
2803-
}
2804-
}
2805-
2806-
return 0;
2807-
}
2779+
bool HasNonStandardAddedArgs(Compiler* compiler) const;
2780+
int GetNonStandardAddedArgCount(Compiler* compiler) const;
28082781
#endif // !LEGACY_BACKEND
28092782

28102783
// Returns true if this call uses a retBuf argument and its calling convention
@@ -2830,7 +2803,7 @@ struct GenTreeCall final : public GenTree
28302803
// will make HasRetBufArg() return true, but will also force the
28312804
// use of register x8 to pass the RetBuf argument.
28322805
//
2833-
bool TreatAsHasRetBufArg(Compiler* compiler);
2806+
bool TreatAsHasRetBufArg(Compiler* compiler) const;
28342807

28352808
//-----------------------------------------------------------------------------------------
28362809
// HasMultiRegRetVal: whether the call node returns its value in multiple return registers.
@@ -2859,57 +2832,60 @@ struct GenTreeCall final : public GenTree
28592832
}
28602833

28612834
// Returns true if VM has flagged this method as CORINFO_FLG_PINVOKE.
2862-
bool IsPInvoke() { return (gtCallMoreFlags & GTF_CALL_M_PINVOKE) != 0; }
2835+
bool IsPInvoke() const { return (gtCallMoreFlags & GTF_CALL_M_PINVOKE) != 0; }
28632836

28642837
// Note that the distinction of whether tail prefixed or an implicit tail call
28652838
// is maintained on a call node till fgMorphCall() after which it will be
28662839
// either a tail call (i.e. IsTailCall() is true) or a non-tail call.
2867-
bool IsTailPrefixedCall() { return (gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL) != 0; }
2840+
bool IsTailPrefixedCall() const { return (gtCallMoreFlags & GTF_CALL_M_EXPLICIT_TAILCALL) != 0; }
28682841

28692842
// This method returning "true" implies that tail call flowgraph morhphing has
28702843
// performed final checks and committed to making a tail call.
2871-
bool IsTailCall() { return (gtCallMoreFlags & GTF_CALL_M_TAILCALL) != 0; }
2844+
bool IsTailCall() const { return (gtCallMoreFlags & GTF_CALL_M_TAILCALL) != 0; }
28722845

28732846
// This method returning "true" implies that importer has performed tail call checks
28742847
// and providing a hint that this can be converted to a tail call.
2875-
bool CanTailCall() { return IsTailPrefixedCall() || IsImplicitTailCall(); }
2848+
bool CanTailCall() const { return IsTailPrefixedCall() || IsImplicitTailCall(); }
28762849

28772850
#ifndef LEGACY_BACKEND
2878-
bool IsTailCallViaHelper() { return IsTailCall() && (gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); }
2851+
bool IsTailCallViaHelper() const { return IsTailCall() && (gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); }
28792852
#else // LEGACY_BACKEND
2880-
bool IsTailCallViaHelper() { return true; }
2853+
bool IsTailCallViaHelper() const { return true; }
28812854
#endif // LEGACY_BACKEND
28822855

28832856
#if FEATURE_FASTTAILCALL
2884-
bool IsFastTailCall() { return IsTailCall() && !(gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); }
2857+
bool IsFastTailCall() const { return IsTailCall() && !(gtCallMoreFlags & GTF_CALL_M_TAILCALL_VIA_HELPER); }
28852858
#else // !FEATURE_FASTTAILCALL
2886-
bool IsFastTailCall() { return false; }
2859+
bool IsFastTailCall() const { return false; }
28872860
#endif // !FEATURE_FASTTAILCALL
28882861

28892862
#if FEATURE_TAILCALL_OPT
28902863
// Returns true if this is marked for opportunistic tail calling.
28912864
// That is, can be tail called though not explicitly prefixed with "tail" prefix.
2892-
bool IsImplicitTailCall() { return (gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL) != 0; }
2893-
bool IsTailCallConvertibleToLoop() { return (gtCallMoreFlags & GTF_CALL_M_TAILCALL_TO_LOOP) != 0; }
2865+
bool IsImplicitTailCall() const { return (gtCallMoreFlags & GTF_CALL_M_IMPLICIT_TAILCALL) != 0; }
2866+
bool IsTailCallConvertibleToLoop() const { return (gtCallMoreFlags & GTF_CALL_M_TAILCALL_TO_LOOP) != 0; }
28942867
#else // !FEATURE_TAILCALL_OPT
2895-
bool IsImplicitTailCall() { return false; }
2896-
bool IsTailCallConvertibleToLoop() { return false; }
2868+
bool IsImplicitTailCall() const { return false; }
2869+
bool IsTailCallConvertibleToLoop() const { return false; }
28972870
#endif // !FEATURE_TAILCALL_OPT
28982871

2899-
bool IsSameThis() { return (gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS) != 0; }
2900-
bool IsDelegateInvoke(){ return (gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV) != 0; }
2901-
bool IsVirtualStubRelativeIndir() { return (gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0; }
2872+
bool IsSameThis() const { return (gtCallMoreFlags & GTF_CALL_M_NONVIRT_SAME_THIS) != 0; }
2873+
bool IsDelegateInvoke() const { return (gtCallMoreFlags & GTF_CALL_M_DELEGATE_INV) != 0; }
2874+
bool IsVirtualStubRelativeIndir() const { return (gtCallMoreFlags & GTF_CALL_M_VIRTSTUB_REL_INDIRECT) != 0; }
2875+
29022876
#ifdef FEATURE_READYTORUN_COMPILER
2903-
bool IsR2RRelativeIndir() { return (gtCallMoreFlags & GTF_CALL_M_R2R_REL_INDIRECT) != 0; }
2904-
void setEntryPoint(CORINFO_CONST_LOOKUP entryPoint) {
2877+
bool IsR2RRelativeIndir() const { return (gtCallMoreFlags & GTF_CALL_M_R2R_REL_INDIRECT) != 0; }
2878+
void setEntryPoint(CORINFO_CONST_LOOKUP entryPoint)
2879+
{
29052880
gtEntryPoint = entryPoint;
29062881
if (gtEntryPoint.accessType == IAT_PVALUE)
29072882
{
29082883
gtCallMoreFlags |= GTF_CALL_M_R2R_REL_INDIRECT;
29092884
}
29102885
}
29112886
#endif // FEATURE_READYTORUN_COMPILER
2912-
bool IsVarargs() { return (gtCallMoreFlags & GTF_CALL_M_VARARGS) != 0; }
2887+
2888+
bool IsVarargs() const { return (gtCallMoreFlags & GTF_CALL_M_VARARGS) != 0; }
29132889

29142890
unsigned short gtCallMoreFlags; // in addition to gtFlags
29152891

@@ -2951,6 +2927,18 @@ struct GenTreeCall final : public GenTree
29512927
// IL offset of the call wrt its parent method.
29522928
IL_OFFSET gtRawILOffset;
29532929
#endif // defined(DEBUG) || defined(INLINE_DATA)
2930+
2931+
bool IsHelperCall() const
2932+
{
2933+
return gtCallType == CT_HELPER;
2934+
}
2935+
2936+
bool IsHelperCall(CORINFO_METHOD_HANDLE callMethHnd) const
2937+
{
2938+
return IsHelperCall() && (callMethHnd == gtCallMethHnd);
2939+
}
2940+
2941+
bool IsHelperCall(Compiler* compiler, unsigned helper) const;
29542942

29552943
GenTreeCall(var_types type) :
29562944
GenTree(GT_CALL, type)

src/jit/lower.cpp

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,26 +2450,7 @@ void Lowering::LowerFastTailCall(GenTreeCall *call)
24502450
// accounted in caller's arg count but accounted in callee's arg count after
24512451
// fgMorphArgs(). Therefore, exclude callee's non-standard args while mapping
24522452
// callee's stack arg num to corresponding caller's stack arg num.
2453-
unsigned calleeNonStandardArgCount = call->GetNonStandardArgCount();
2454-
2455-
#ifdef DEBUG
2456-
// cross check non-standard arg count.
2457-
if (firstPutArgStk && call->HasNonStandardArgs())
2458-
{
2459-
fgArgInfoPtr argInfo = call->gtCall.fgArgInfo;
2460-
unsigned argCount = argInfo->ArgCount();
2461-
fgArgTabEntryPtr * argTable = argInfo->ArgTable();
2462-
2463-
unsigned cnt = 0;
2464-
for (unsigned i=0; i < argCount; i++)
2465-
{
2466-
if (argTable[i]->isNonStandard)
2467-
++cnt;
2468-
}
2469-
assert(cnt == calleeNonStandardArgCount);
2470-
}
2471-
#endif
2472-
2453+
unsigned calleeNonStandardArgCount = call->GetNonStandardAddedArgCount(comp);
24732454

24742455
// Say Caller(a, b, c, d, e) fast tail calls Callee(e, d, c, b, a)
24752456
// i.e. passes its arguments in reverse to Callee. During call site
@@ -3135,7 +3116,7 @@ void Lowering::InsertPInvokeMethodProlog()
31353116
GenTree* lastStmt = stmt;
31363117
DISPTREE(lastStmt);
31373118

3138-
#ifndef _TARGET_X86_ // For x86, this step is done at the call site.
3119+
#ifndef _TARGET_X86_ // For x86, this step is done at the call site (due to stack pointer not being static in the function).
31393120

31403121
// --------------------------------------------------------
31413122
// InlinedCallFrame.m_pCallSiteSP = @RSP;

src/jit/lowerxarch.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1073,7 +1073,7 @@ Lowering::TreeNodeInfoInitCall(GenTreeCall* call)
10731073

10741074
// Set destination candidates for return value of the call.
10751075
#ifdef _TARGET_X86_
1076-
if ((call->gtCallType == CT_HELPER) && (call->gtCallMethHnd == compiler->eeFindHelper(CORINFO_HELP_INIT_PINVOKE_FRAME)))
1076+
if (call->IsHelperCall(compiler, CORINFO_HELP_INIT_PINVOKE_FRAME))
10771077
{
10781078
// The x86 CORINFO_HELP_INIT_PINVOKE_FRAME helper uses a custom calling convention that returns with
10791079
// TCB in REG_PINVOKE_TCB. AMD64/ARM64 use the standard calling convention. fgMorphCall() sets the

0 commit comments

Comments
 (0)