@@ -600,8 +600,11 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo
600600 }
601601}
602602
603- // Gets a register mask that represent the kill set for a helper call since
604- // not all JIT Helper calls follow the standard ABI on the target architecture.
603+ // ----------------------------------------------------------------------
604+ // compNoGCHelperCallKillSet:
605+ //
606+ // Gets a register mask that represents the kill set for a helper call.
607+ // Not all JIT Helper calls follow the standard ABI on the target architecture.
605608//
606609// TODO-CQ: Currently this list is incomplete (not all helpers calls are
607610// enumerated) and not 100% accurate (some killsets are bigger than
@@ -624,19 +627,24 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo
624627//
625628// The interim solution is to only add known helper calls that don't
626629// follow the AMD64 ABI and actually trash registers that are supposed to be non-volatile.
630+ //
631+ // Arguments:
632+ // helper - The helper being inquired about
633+ //
634+ // Return Value:
635+ // Mask of register kills -- registers whose value is no longer guaranteed to be the same.
636+ //
627637regMaskTP Compiler::compHelperCallKillSet (CorInfoHelpFunc helper)
628638{
629639 switch (helper)
630640 {
631641 case CORINFO_HELP_ASSIGN_BYREF:
632642#if defined(_TARGET_AMD64_)
633- return RBM_RSI | RBM_RDI | RBM_CALLEE_TRASH ;
634- #elif defined(_TARGET_ARM64_ )
643+ return RBM_RSI | RBM_RDI | RBM_CALLEE_TRASH_NOGC ;
644+ #elif defined(_TARGET_ARMARCH_ )
635645 return RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF | RBM_CALLEE_TRASH_NOGC;
636646#elif defined(_TARGET_X86_)
637647 return RBM_ESI | RBM_EDI | RBM_ECX;
638- #elif defined(_TARGET_ARM_)
639- return RBM_ARG_1 | RBM_ARG_0 | RBM_CALLEE_TRASH_NOGC;
640648#else
641649 NYI (" Model kill set for CORINFO_HELP_ASSIGN_BYREF on target arch" );
642650 return RBM_CALLEE_TRASH;
@@ -663,6 +671,29 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
663671 NYI (" Model kill set for CORINFO_HELP_PROF_FCN_TAILCALL on target arch" );
664672#endif
665673
674+ #ifdef _TARGET_X86_
675+ case CORINFO_HELP_ASSIGN_REF_EAX:
676+ case CORINFO_HELP_ASSIGN_REF_ECX:
677+ case CORINFO_HELP_ASSIGN_REF_EBX:
678+ case CORINFO_HELP_ASSIGN_REF_EBP:
679+ case CORINFO_HELP_ASSIGN_REF_ESI:
680+ case CORINFO_HELP_ASSIGN_REF_EDI:
681+
682+ case CORINFO_HELP_CHECKED_ASSIGN_REF_EAX:
683+ case CORINFO_HELP_CHECKED_ASSIGN_REF_ECX:
684+ case CORINFO_HELP_CHECKED_ASSIGN_REF_EBX:
685+ case CORINFO_HELP_CHECKED_ASSIGN_REF_EBP:
686+ case CORINFO_HELP_CHECKED_ASSIGN_REF_ESI:
687+ case CORINFO_HELP_CHECKED_ASSIGN_REF_EDI:
688+ return RBM_EDX;
689+
690+ #ifdef FEATURE_USE_ASM_GC_WRITE_BARRIERS
691+ case CORINFO_HELP_ASSIGN_REF:
692+ case CORINFO_HELP_CHECKED_ASSIGN_REF:
693+ return RBM_EAX | RBM_EDX;
694+ #endif // FEATURE_USE_ASM_GC_WRITE_BARRIERS
695+ #endif
696+
666697 case CORINFO_HELP_STOP_FOR_GC:
667698 return RBM_STOP_FOR_GC_TRASH;
668699
@@ -674,19 +705,30 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
674705 }
675706}
676707
708+ // ----------------------------------------------------------------------
709+ // compNoGCHelperCallKillSet: Gets a register mask that represents the set of registers that no longer
710+ // contain GC or byref pointers, for "NO GC" helper calls. This is used by the emitter when determining
711+ // what registers to remove from the current live GC/byref sets (and thus what to report as dead in the
712+ // GC info). Note that for the CORINFO_HELP_ASSIGN_BYREF helper, in particular, the kill set reported by
713+ // compHelperCallKillSet() doesn't match this kill set. compHelperCallKillSet() reports the dst/src
714+ // address registers as killed for liveness purposes, since their values change. However, they still are
715+ // valid byref pointers after the call, so the dst/src address registers are NOT reported as killed here.
716+ //
717+ // Note: This list may not be complete and defaults to the default RBM_CALLEE_TRASH_NOGC registers.
677718//
678- // Gets a register mask that represents the kill set for "NO GC" helper calls since
679- // not all JIT Helper calls follow the standard ABI on the target architecture.
719+ // Arguments:
720+ // helper - The helper being inquired about
680721//
681- // Note: This list may not be complete and defaults to the default NOGC registers.
722+ // Return Value:
723+ // Mask of GC register kills
682724//
683725regMaskTP Compiler::compNoGCHelperCallKillSet (CorInfoHelpFunc helper)
684726{
685727 assert (emitter::emitNoGChelper (helper));
686728
687729 switch (helper)
688730 {
689- #if defined(_TARGET_AMD64_) || defined(_TARGET_X86_ )
731+ #if defined(_TARGET_XARCH_ )
690732 case CORINFO_HELP_PROF_FCN_ENTER:
691733 return RBM_PROFILER_ENTER_TRASH;
692734
@@ -695,18 +737,15 @@ regMaskTP Compiler::compNoGCHelperCallKillSet(CorInfoHelpFunc helper)
695737
696738 case CORINFO_HELP_PROF_FCN_TAILCALL:
697739 return RBM_PROFILER_TAILCALL_TRASH;
698- #endif // defined(_TARGET_AMD64_) || defined(_TARGET_X86_ )
740+ #endif // defined(_TARGET_XARCH_ )
699741
700742 case CORINFO_HELP_ASSIGN_BYREF:
701743#if defined(_TARGET_AMD64_)
702- // this helper doesn't trash RSI and RDI
703- return RBM_CALLEE_TRASH_NOGC & ~(RBM_RSI | RBM_RDI);
744+ return RBM_CALLEE_TRASH_NOGC;
704745#elif defined(_TARGET_X86_)
705746 // This helper only trashes ECX.
706747 return RBM_ECX;
707- #elif defined(_TARGET_ARM64_)
708- return RBM_CALLEE_TRASH_NOGC & ~(RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF);
709- #else
748+ #elif defined(_TARGET_ARMARCH_)
710749 return RBM_CALLEE_TRASH_NOGC;
711750#endif // defined(_TARGET_AMD64_)
712751
@@ -3912,16 +3951,86 @@ void CodeGen::genReportEH()
39123951 assert (XTnum == EHCount);
39133952}
39143953
3915- void CodeGen::genGCWriteBarrier (GenTreePtr tgt, GCInfo::WriteBarrierForm wbf)
3954+ // ----------------------------------------------------------------------
3955+ // genUseOptimizedWriteBarriers: Determine if an optimized write barrier
3956+ // helper should be used.
3957+ //
3958+ // Arguments:
3959+ // wbf - The WriteBarrierForm of the write (GT_STOREIND) that is happening.
3960+ //
3961+ // Return Value:
3962+ // true if an optimized write barrier helper should be used, false otherwise.
3963+ // Note: only x86 implements (register-specific source) optimized write
3964+ // barriers currently).
3965+ //
3966+ bool CodeGenInterface::genUseOptimizedWriteBarriers (GCInfo::WriteBarrierForm wbf)
3967+ {
3968+ #if defined(_TARGET_X86_) && NOGC_WRITE_BARRIERS
3969+ #ifdef DEBUG
3970+ return (wbf != GCInfo::WBF_NoBarrier_CheckNotHeapInDebug); // This one is always a call to a C++ method.
3971+ #else // !DEBUG
3972+ return true ;
3973+ #endif // !DEBUG
3974+ #else // !defined(_TARGET_X86_) || !NOGC_WRITE_BARRIERS
3975+ return false ;
3976+ #endif !defined (_TARGET_X86_) || !NOGC_WRITE_BARRIERS
3977+ }
3978+
3979+ // ----------------------------------------------------------------------
3980+ // genUseOptimizedWriteBarriers: Determine if an optimized write barrier
3981+ // helper should be used.
3982+ //
3983+ // This has the same functionality as the version of
3984+ // genUseOptimizedWriteBarriers that takes a WriteBarrierForm, but avoids
3985+ // determining what the required write barrier form is, if possible.
3986+ //
3987+ // Arguments:
3988+ // tgt - target tree of write (e.g., GT_STOREIND)
3989+ // assignVal - tree with value to write
3990+ //
3991+ // Return Value:
3992+ // true if an optimized write barrier helper should be used, false otherwise.
3993+ // Note: only x86 implements (register-specific source) optimized write
3994+ // barriers currently).
3995+ //
3996+ bool CodeGenInterface::genUseOptimizedWriteBarriers (GenTree* tgt, GenTree* assignVal)
3997+ {
3998+ #if defined(_TARGET_X86_) && NOGC_WRITE_BARRIERS
3999+ #ifdef DEBUG
4000+ GCInfo::WriteBarrierForm wbf = compiler->codeGen ->gcInfo .gcIsWriteBarrierCandidate (tgt, assignVal);
4001+ return (wbf != GCInfo::WBF_NoBarrier_CheckNotHeapInDebug); // This one is always a call to a C++ method.
4002+ #else // !DEBUG
4003+ return true ;
4004+ #endif // !DEBUG
4005+ #else
4006+ return false ;
4007+ #endif
4008+ }
4009+
4010+ // ----------------------------------------------------------------------
4011+ // genWriteBarrierHelperForWriteBarrierForm: Given a write node requiring a write
4012+ // barrier, and the write barrier form required, determine the helper to call.
4013+ //
4014+ // Arguments:
4015+ // tgt - target tree of write (e.g., GT_STOREIND)
4016+ // wbf - already computed write barrier form to use
4017+ //
4018+ // Return Value:
4019+ // Write barrier helper to use.
4020+ //
4021+ // Note: do not call this function to get an optimized write barrier helper (e.g.,
4022+ // for x86).
4023+ //
4024+ CorInfoHelpFunc CodeGenInterface::genWriteBarrierHelperForWriteBarrierForm (GenTree* tgt, GCInfo::WriteBarrierForm wbf)
39164025{
39174026#ifndef LEGACY_BACKEND
39184027 noway_assert (tgt->gtOper == GT_STOREIND);
39194028#else // LEGACY_BACKEND
39204029 noway_assert (tgt->gtOper == GT_IND || tgt->gtOper == GT_CLS_VAR); // enforced by gcIsWriteBarrierCandidate
39214030#endif // LEGACY_BACKEND
39224031
3923- /* Call the proper vm helper */
3924- int helper = CORINFO_HELP_ASSIGN_REF;
4032+ CorInfoHelpFunc helper = CORINFO_HELP_ASSIGN_REF;
4033+
39254034#ifdef DEBUG
39264035 if (wbf == GCInfo::WBF_NoBarrier_CheckNotHeapInDebug)
39274036 {
@@ -3949,6 +4058,20 @@ void CodeGen::genGCWriteBarrier(GenTreePtr tgt, GCInfo::WriteBarrierForm wbf)
39494058 ((helper == CORINFO_HELP_ASSIGN_REF) &&
39504059 (wbf == GCInfo::WBF_BarrierUnchecked || wbf == GCInfo::WBF_BarrierUnknown)));
39514060
4061+ return helper;
4062+ }
4063+
4064+ // ----------------------------------------------------------------------
4065+ // genGCWriteBarrier: Generate a write barrier for a node.
4066+ //
4067+ // Arguments:
4068+ // tgt - target tree of write (e.g., GT_STOREIND)
4069+ // wbf - already computed write barrier form to use
4070+ //
4071+ void CodeGen::genGCWriteBarrier (GenTreePtr tgt, GCInfo::WriteBarrierForm wbf)
4072+ {
4073+ CorInfoHelpFunc helper = genWriteBarrierHelperForWriteBarrierForm (tgt, wbf);
4074+
39524075#ifdef FEATURE_COUNT_GC_WRITE_BARRIERS
39534076 // We classify the "tgt" trees as follows:
39544077 // If "tgt" is of the form (where [ x ] indicates an optional x, and { x1, ..., xn } means "one of the x_i forms"):
0 commit comments