Fix/clean compNoGCHelperCallKillSet for arm. (dotnet/coreclr#23078)
authorSergey Andreenko <seandree@microsoft.com>
Thu, 14 Mar 2019 01:31:27 +0000 (18:31 -0700)
committerGitHub <noreply@github.com>
Thu, 14 Mar 2019 01:31:27 +0000 (18:31 -0700)
* Add an assert to compNoGCHelperCallKillSet.

That registers that lose GC or byref values also are in compHelperCallKillSet return set.

* Move compNoGCHelperCallKillSet from compiler to emitter.

* Rename `compNoGCHelperCallKillSet` to `emitGetGCRegsKilledByNoGCCall`.

* Fix GCRegsKill sets for arm CORINFO_HELP_PROF_FCN_ENTER and CORINFO_HELP_PROF_FCN_LEAVE.

Commit migrated from https://github.com/dotnet/coreclr/commit/83327daf3c6186587f91182c39afd8e768baecfd

src/coreclr/src/jit/codegencommon.cpp
src/coreclr/src/jit/compiler.h
src/coreclr/src/jit/emit.cpp
src/coreclr/src/jit/emit.h

index 55028e9..a457103 100644 (file)
@@ -618,72 +618,6 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
     }
 }
 
-//----------------------------------------------------------------------
-// compNoGCHelperCallKillSet: Gets a register mask that represents the set of registers that no longer
-// contain GC or byref pointers, for "NO GC" helper calls. This is used by the emitter when determining
-// what registers to remove from the current live GC/byref sets (and thus what to report as dead in the
-// GC info). Note that for the CORINFO_HELP_ASSIGN_BYREF helper, in particular, the kill set reported by
-// compHelperCallKillSet() doesn't match this kill set. compHelperCallKillSet() reports the dst/src
-// address registers as killed for liveness purposes, since their values change. However, they still are
-// valid byref pointers after the call, so the dst/src address registers are NOT reported as killed here.
-//
-// Note: This list may not be complete and defaults to the default RBM_CALLEE_TRASH_NOGC registers.
-//
-// Arguments:
-//   helper - The helper being inquired about
-//
-// Return Value:
-//   Mask of GC register kills
-//
-regMaskTP Compiler::compNoGCHelperCallKillSet(CorInfoHelpFunc helper)
-{
-    assert(emitter::emitNoGChelper(helper));
-
-    switch (helper)
-    {
-        case CORINFO_HELP_ASSIGN_BYREF:
-#if defined(_TARGET_X86_)
-            // This helper only trashes ECX.
-            return RBM_ECX;
-#elif defined(_TARGET_AMD64_)
-            // This uses and defs RDI and RSI.
-            return RBM_CALLEE_TRASH_NOGC & ~(RBM_RDI | RBM_RSI);
-#elif defined(_TARGET_ARMARCH_)
-            return RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF;
-#else
-            assert(!"unknown arch");
-#endif
-
-#if defined(_TARGET_XARCH_)
-        case CORINFO_HELP_PROF_FCN_ENTER:
-            return RBM_PROFILER_ENTER_TRASH;
-
-        case CORINFO_HELP_PROF_FCN_LEAVE:
-            return RBM_PROFILER_LEAVE_TRASH;
-
-        case CORINFO_HELP_PROF_FCN_TAILCALL:
-            return RBM_PROFILER_TAILCALL_TRASH;
-#endif // defined(_TARGET_XARCH_)
-
-#if defined(_TARGET_ARMARCH_)
-        case CORINFO_HELP_ASSIGN_REF:
-        case CORINFO_HELP_CHECKED_ASSIGN_REF:
-            return RBM_CALLEE_GCTRASH_WRITEBARRIER;
-        case CORINFO_HELP_PROF_FCN_LEAVE:
-            // In case of Leave profiler callback, we need to preserve liveness of REG_PROFILER_RET_SCRATCH on ARMARCH.
-            return RBM_CALLEE_TRASH_NOGC & ~RBM_PROFILER_RET_SCRATCH;
-#endif
-
-#if defined(_TARGET_X86_)
-        case CORINFO_HELP_INIT_PINVOKE_FRAME:
-            return RBM_INIT_PINVOKE_FRAME_TRASH;
-#endif // defined(_TARGET_X86_)
-
-        default:
-            return RBM_CALLEE_TRASH_NOGC;
-    }
-}
-
 template <bool ForCodeGen>
 void Compiler::compChangeLife(VARSET_VALARG_TP newLife)
 {
index 8c2b945..d6edd64 100644 (file)
@@ -7195,9 +7195,6 @@ public:
     // not all JIT Helper calls follow the standard ABI on the target architecture.
     regMaskTP compHelperCallKillSet(CorInfoHelpFunc helper);
 
-    // Gets a register mask that represent the kill set for a NoGC helper call.
-    regMaskTP compNoGCHelperCallKillSet(CorInfoHelpFunc helper);
-
 #ifdef _TARGET_ARM_
     // Requires that "varDsc" be a promoted struct local variable being passed as an argument, beginning at
     // "firstArgRegNum", which is assumed to have already been aligned to the register alignment restriction of the
index db6aa10..982417d 100644 (file)
@@ -7481,7 +7481,7 @@ regMaskTP emitter::emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd)
         CorInfoHelpFunc helpFunc = Compiler::eeGetHelperNum(methHnd);
 
         // Get the set of registers that this call kills and remove it from the saved set.
-        regMaskTP savedSet = RBM_ALLINT & ~emitComp->compNoGCHelperCallKillSet(helpFunc);
+        regMaskTP savedSet = RBM_ALLINT & ~emitGetGCRegsKilledByNoGCCall(helpFunc);
 
 #ifdef DEBUG
         if (emitComp->verbose)
@@ -7500,3 +7500,82 @@ regMaskTP emitter::emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd)
         return RBM_CALLEE_SAVED;
     }
 }
+
+//----------------------------------------------------------------------
+// emitGetGCRegsKilledByNoGCCall: Gets a register mask that represents the set of registers that no longer
+// contain GC or byref pointers, for "NO GC" helper calls. This is used by the emitter when determining
+// what registers to remove from the current live GC/byref sets (and thus what to report as dead in the
+// GC info). Note that for the CORINFO_HELP_ASSIGN_BYREF helper, in particular, the kill set reported by
+// compHelperCallKillSet() doesn't match this kill set. compHelperCallKillSet() reports the dst/src
+// address registers as killed for liveness purposes, since their values change. However, they still are
+// valid byref pointers after the call, so the dst/src address registers are NOT reported as killed here.
+//
+// Note: This list may not be complete and defaults to the default RBM_CALLEE_TRASH_NOGC registers.
+//
+// Arguments:
+//   helper - The helper being inquired about
+//
+// Return Value:
+//   Mask of GC register kills
+//
+regMaskTP emitter::emitGetGCRegsKilledByNoGCCall(CorInfoHelpFunc helper)
+{
+    assert(emitNoGChelper(helper));
+    regMaskTP result;
+    switch (helper)
+    {
+        case CORINFO_HELP_ASSIGN_BYREF:
+#if defined(_TARGET_X86_)
+            // This helper only trashes ECX.
+            result = RBM_ECX;
+            break;
+#elif defined(_TARGET_AMD64_)
+            // This uses and defs RDI and RSI.
+            result = RBM_CALLEE_TRASH_NOGC & ~(RBM_RDI | RBM_RSI);
+            break;
+#elif defined(_TARGET_ARMARCH_)
+            result = RBM_CALLEE_GCTRASH_WRITEBARRIER_BYREF;
+            break;
+#else
+            assert(!"unknown arch");
+#endif
+
+#if defined(_TARGET_XARCH_) || defined(_TARGET_ARM_)
+        case CORINFO_HELP_PROF_FCN_ENTER:
+            result = RBM_PROFILER_ENTER_TRASH;
+            break;
+
+        case CORINFO_HELP_PROF_FCN_LEAVE:
+            result = RBM_PROFILER_LEAVE_TRASH;
+            break;
+#if defined(_TARGET_XARCH_)
+        case CORINFO_HELP_PROF_FCN_TAILCALL:
+            result = RBM_PROFILER_TAILCALL_TRASH;
+            break;
+#endif // defined(_TARGET_XARCH_)
+#endif // defined(_TARGET_XARCH_) || defined(_TARGET_ARM_)
+
+#if defined(_TARGET_ARMARCH_)
+        case CORINFO_HELP_ASSIGN_REF:
+        case CORINFO_HELP_CHECKED_ASSIGN_REF:
+            result = RBM_CALLEE_GCTRASH_WRITEBARRIER;
+            break;
+#endif // defined(_TARGET_ARMARCH_)
+
+#if defined(_TARGET_X86_)
+        case CORINFO_HELP_INIT_PINVOKE_FRAME:
+            result = RBM_INIT_PINVOKE_FRAME_TRASH;
+            break;
+#endif // defined(_TARGET_X86_)
+
+        default:
+            result = RBM_CALLEE_TRASH_NOGC;
+            break;
+    }
+
+    // compHelperCallKillSet returns a superset of the registers which values are not guranteed to be the same
+    // after the call, if a register loses its GC or byref it has to be in the compHelperCallKillSet set as well.
+    assert((result & emitComp->compHelperCallKillSet(helper)) == result);
+
+    return result;
+}
index 7d6e43f..876dc08 100644 (file)
@@ -1927,6 +1927,9 @@ public:
 
     regMaskTP emitGetGCRegsSavedOrModified(CORINFO_METHOD_HANDLE methHnd);
 
+    // Gets a register mask that represent the kill set for a NoGC helper call.
+    regMaskTP emitGetGCRegsKilledByNoGCCall(CorInfoHelpFunc helper);
+
 #if EMIT_TRACK_STACK_DEPTH
     unsigned emitCntStackDepth; // 0 in prolog/epilog, One DWORD elsewhere
     unsigned emitMaxStackDepth; // actual computed max. stack depth