From 83327daf3c6186587f91182c39afd8e768baecfd Mon Sep 17 00:00:00 2001 From: Sergey Andreenko Date: Wed, 13 Mar 2019 18:31:27 -0700 Subject: Fix/clean compNoGCHelperCallKillSet for arm. (#23078) * 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. --- src/jit/codegencommon.cpp | 66 -------------------------------------- src/jit/compiler.h | 3 -- src/jit/emit.cpp | 81 ++++++++++++++++++++++++++++++++++++++++++++++- src/jit/emit.h | 3 ++ 4 files changed, 83 insertions(+), 70 deletions(-) diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp index 55028e9e82..a45710330f 100644 --- a/src/jit/codegencommon.cpp +++ b/src/jit/codegencommon.cpp @@ -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 void Compiler::compChangeLife(VARSET_VALARG_TP newLife) { diff --git a/src/jit/compiler.h b/src/jit/compiler.h index 8c2b945863..d6edd6483f 100644 --- a/src/jit/compiler.h +++ b/src/jit/compiler.h @@ -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 diff --git a/src/jit/emit.cpp b/src/jit/emit.cpp index db6aa10112..982417d9d6 100644 --- a/src/jit/emit.cpp +++ b/src/jit/emit.cpp @@ -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; +} diff --git a/src/jit/emit.h b/src/jit/emit.h index 7d6e43f90f..876dc085fc 100644 --- a/src/jit/emit.h +++ b/src/jit/emit.h @@ -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 -- cgit v1.2.3