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

Commit d415a00

Browse files
committed
Address P/Invoke inlining code review feedback and cleanup
Address some code review feedback from #5939. Also, do a little cleanup. Specifically: 1. Make many GenTreeCall accessors 'const'. 2. HasNonStandardArgs() and GetNonStandardArgCount() are used for a specific purpose in the fast tailcall implementation. However, the fgMorphArgs() "non-standard args" mechanism is now used for other purposes, so the names of these didn't match their intent. Also, the logic had decayed compared to the fgMorphArgs logic it was mimicing. I renamed them to add the word "Added", and wrote some comments to be more explicit about their use, as well as indicate in fgMorphArgs() that they need to be kept in sync. 3. Added several GenTreeCall::IsHelperCall() accessors, and replace some code with them. 4. Added RBM_INIT_PINVOKE_FRAME_TRASH define to remove an `#ifdef`. 5. Removed an assert loop in LowerFastTailCall() since it's no longer accurate given the new users of `isNonStandard`.
1 parent 2364d60 commit d415a00

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)