Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakob Botsch Nielsen <Jakob.botsch.nielsen@gmail.com>2021-07-05 13:23:00 +0300
committerGitHub <noreply@github.com>2021-07-05 13:23:00 +0300
commit66c339b0be0d544e092fa54047070a25d2d3b4f3 (patch)
tree284d71a22dcd1a82b5a97f9fbfa9924abd81371e /src/coreclr
parent5c340e9ade0baf7f3c0aa0a9128bf36b158fe7d6 (diff)
Allow implicit widenings when tailcalling (#54864)
The managed calling convention dictates that the callee is responsible for widening up to 4 bytes. We can use this to allow some more tailcalls. Fix #51957
Diffstat (limited to 'src/coreclr')
-rw-r--r--src/coreclr/jit/importer.cpp20
-rw-r--r--src/coreclr/jit/morph.cpp13
2 files changed, 17 insertions, 16 deletions
diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp
index 66998450dbd..f65eb39fddc 100644
--- a/src/coreclr/jit/importer.cpp
+++ b/src/coreclr/jit/importer.cpp
@@ -7874,14 +7874,24 @@ bool Compiler::impTailCallRetTypeCompatible(var_types callerRetTy
CORINFO_CLASS_HANDLE calleeRetTypeClass,
CorInfoCallConvExtension calleeCallConv)
{
- // Note that we can not relax this condition with genActualType() as the
- // calling convention dictates that the caller of a function with a small
- // typed return value is responsible for normalizing the return val.
+ // Early out if the types are the same.
if (callerRetType == calleeRetType)
{
return true;
}
+ // For integral types the managed calling convention dictates that callee
+ // will widen the return value to 4 bytes, so we can allow implicit widening
+ // in managed to managed tailcalls when dealing with <= 4 bytes.
+ bool isManaged =
+ (callerCallConv == CorInfoCallConvExtension::Managed) && (calleeCallConv == CorInfoCallConvExtension::Managed);
+
+ if (isManaged && varTypeIsIntegral(callerRetType) && varTypeIsIntegral(calleeRetType) &&
+ (genTypeSize(callerRetType) <= 4) && (genTypeSize(calleeRetType) <= genTypeSize(callerRetType)))
+ {
+ return true;
+ }
+
// If the class handles are the same and not null, the return types are compatible.
if ((callerRetTypeClass != nullptr) && (callerRetTypeClass == calleeRetTypeClass))
{
@@ -8672,7 +8682,9 @@ var_types Compiler::impImportCall(OPCODE opcode,
if (call->gtFlags & GTF_CALL_UNMANAGED)
{
// We set up the unmanaged call by linking the frame, disabling GC, etc
- // This needs to be cleaned up on return
+ // This needs to be cleaned up on return.
+ // In addition, native calls have different normalization rules than managed code
+ // (managed calling convention always widens return values in the callee)
if (canTailCall)
{
canTailCall = false;
diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp
index 4ec1328f878..8f571377489 100644
--- a/src/coreclr/jit/morph.cpp
+++ b/src/coreclr/jit/morph.cpp
@@ -6804,18 +6804,7 @@ void Compiler::fgMorphCallInlineHelper(GenTreeCall* call, InlineResult* result)
// structs being passed to either the caller or callee.
//
// Exceptions:
-// 1) If the callee has structs which cannot be enregistered it will be
-// reported as cannot fast tail call. This is an implementation limitation
-// where the callee only is checked for non enregisterable structs. This is
-// tracked with https://github.com/dotnet/runtime/issues/8492.
-//
-// 2) If the caller or callee has stack arguments and the callee has more
-// arguments then the caller it will be reported as cannot fast tail call.
-// This is due to a bug in LowerFastTailCall which assumes that
-// nCalleeArgs <= nCallerArgs, which is always true on Windows Amd64. This
-// is tracked with https://github.com/dotnet/runtime/issues/8413.
-//
-// 3) If the callee has a 9 to 16 byte struct argument and the callee has
+// If the callee has a 9 to 16 byte struct argument and the callee has
// stack arguments, the decision will be to not fast tail call. This is
// because before fgMorphArgs is done, the struct is unknown whether it
// will be placed on the stack or enregistered. Therefore, the conservative