diff --git a/src/coreclr/src/jit/codegenarmarch.cpp b/src/coreclr/src/jit/codegenarmarch.cpp index cacfb1a6182db2..9ca28936f24bf9 100644 --- a/src/coreclr/src/jit/codegenarmarch.cpp +++ b/src/coreclr/src/jit/codegenarmarch.cpp @@ -2520,13 +2520,14 @@ void CodeGen::genCallInstruction(GenTreeCall* call) INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, target->GetRegNum()); } -#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) - else if (call->IsR2RRelativeIndir()) + else if (call->IsR2ROrVirtualStubRelativeIndir()) { // Generate a direct call to a non-virtual user defined or helper method assert(callType == CT_HELPER || callType == CT_USER_FUNC); - assert(call->gtEntryPoint.accessType == IAT_PVALUE); + assert(((call->IsR2RRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_PVALUE)) || + ((call->IsVirtualStubRelativeIndir()) && (call->gtEntryPoint.accessType == IAT_VALUE))); assert(call->gtControlExpr == nullptr); + assert(!call->IsTailCall()); regNumber tmpReg = call->GetSingleTempReg(); GetEmitter()->emitIns_R_R(ins_Load(TYP_I_IMPL), emitActualTypeSize(TYP_I_IMPL), tmpReg, REG_R2R_INDIRECT_PARAM); @@ -2540,7 +2541,6 @@ void CodeGen::genCallInstruction(GenTreeCall* call) INDEBUG_LDISASM_COMMA(sigInfo) nullptr, // addr retSize MULTIREG_HAS_SECOND_GC_RET_ONLY_ARG(secondRetSize), ilOffset, tmpReg); } -#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH else { // Generate a direct call to a non-virtual user defined or helper method diff --git a/src/coreclr/src/jit/gentree.h b/src/coreclr/src/jit/gentree.h index c43227bd663111..ec0cbee87192e4 100644 --- a/src/coreclr/src/jit/gentree.h +++ b/src/coreclr/src/jit/gentree.h @@ -4202,6 +4202,16 @@ struct GenTreeCall final : public GenTree return (gtFlags & GTF_CALL_INLINE_CANDIDATE) != 0; } + bool IsR2ROrVirtualStubRelativeIndir() + { +#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + bool isVirtualStub = (gtFlags & GTF_CALL_VIRT_KIND_MASK) == GTF_CALL_VIRT_STUB; + return ((IsR2RRelativeIndir()) || (isVirtualStub && (IsVirtualStubRelativeIndir()))); +#else + return false; +#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH + } + bool HasNonStandardAddedArgs(Compiler* compiler) const; int GetNonStandardAddedArgCount(Compiler* compiler) const; diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index 2c093a67d048bb..75d63a18661f7d 100644 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -3489,6 +3489,9 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call) { bool isR2RRelativeIndir = false; #if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + // Skip inserting the indirection node to load the address that is already + // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the + // codegen, just load the call target from REG_R2R_INDIRECT_PARAM. isR2RRelativeIndir = call->IsR2RRelativeIndir(); #endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH @@ -4529,7 +4532,21 @@ GenTree* Lowering::LowerVirtualStubCall(GenTreeCall* call) } else { - result = Ind(addr); + + bool shouldOptimizeVirtualStubCall = false; +#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) + // Skip inserting the indirection node to load the address that is already + // computed in REG_R2R_INDIRECT_PARAM as a hidden parameter. Instead during the + // codegen, just load the call target from REG_R2R_INDIRECT_PARAM. + // However, for tail calls, the call target is always computed in RBM_FASTTAILCALL_TARGET + // and so do not optimize virtual stub calls for such cases. + shouldOptimizeVirtualStubCall = !call->IsTailCall(); +#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH + + if (!shouldOptimizeVirtualStubCall) + { + result = Ind(addr); + } } } diff --git a/src/coreclr/src/jit/lsraarmarch.cpp b/src/coreclr/src/jit/lsraarmarch.cpp index 64d18bf6d80bde..bcc987ca62e132 100644 --- a/src/coreclr/src/jit/lsraarmarch.cpp +++ b/src/coreclr/src/jit/lsraarmarch.cpp @@ -182,12 +182,10 @@ int LinearScan::BuildCall(GenTreeCall* call) ctrlExprCandidates = RBM_FASTTAILCALL_TARGET; } } -#if defined(FEATURE_READYTORUN_COMPILER) && defined(TARGET_ARMARCH) - else if (call->IsR2RRelativeIndir()) + else if (call->IsR2ROrVirtualStubRelativeIndir()) { buildInternalIntRegisterDefForNode(call); } -#endif // FEATURE_READYTORUN_COMPILER && TARGET_ARMARCH #ifdef TARGET_ARM else {