@@ -600,8 +600,11 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo
600
600
}
601
601
}
602
602
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.
605
608
//
606
609
// TODO-CQ: Currently this list is incomplete (not all helpers calls are
607
610
// enumerated) and not 100% accurate (some killsets are bigger than
@@ -624,19 +627,24 @@ void CodeGenInterface::genUpdateRegLife(const LclVarDsc* varDsc, bool isBorn, bo
624
627
//
625
628
// The interim solution is to only add known helper calls that don't
626
629
// 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
+ //
627
637
regMaskTP Compiler::compHelperCallKillSet (CorInfoHelpFunc helper)
628
638
{
629
639
switch (helper)
630
640
{
631
641
case CORINFO_HELP_ASSIGN_BYREF:
632
642
#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_ )
635
645
return RBM_WRITE_BARRIER_SRC_BYREF | RBM_WRITE_BARRIER_DST_BYREF | RBM_CALLEE_TRASH_NOGC;
636
646
#elif defined(_TARGET_X86_)
637
647
return RBM_ESI | RBM_EDI | RBM_ECX;
638
- #elif defined(_TARGET_ARM_)
639
- return RBM_ARG_1 | RBM_ARG_0 | RBM_CALLEE_TRASH_NOGC;
640
648
#else
641
649
NYI (" Model kill set for CORINFO_HELP_ASSIGN_BYREF on target arch" );
642
650
return RBM_CALLEE_TRASH;
@@ -663,6 +671,29 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
663
671
NYI (" Model kill set for CORINFO_HELP_PROF_FCN_TAILCALL on target arch" );
664
672
#endif
665
673
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
+
666
697
case CORINFO_HELP_STOP_FOR_GC:
667
698
return RBM_STOP_FOR_GC_TRASH;
668
699
@@ -674,19 +705,30 @@ regMaskTP Compiler::compHelperCallKillSet(CorInfoHelpFunc helper)
674
705
}
675
706
}
676
707
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.
677
718
//
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
680
721
//
681
- // Note: This list may not be complete and defaults to the default NOGC registers.
722
+ // Return Value:
723
+ // Mask of GC register kills
682
724
//
683
725
regMaskTP Compiler::compNoGCHelperCallKillSet (CorInfoHelpFunc helper)
684
726
{
685
727
assert (emitter::emitNoGChelper (helper));
686
728
687
729
switch (helper)
688
730
{
689
- #if defined(_TARGET_AMD64_) || defined(_TARGET_X86_ )
731
+ #if defined(_TARGET_XARCH_ )
690
732
case CORINFO_HELP_PROF_FCN_ENTER:
691
733
return RBM_PROFILER_ENTER_TRASH;
692
734
@@ -695,18 +737,15 @@ regMaskTP Compiler::compNoGCHelperCallKillSet(CorInfoHelpFunc helper)
695
737
696
738
case CORINFO_HELP_PROF_FCN_TAILCALL:
697
739
return RBM_PROFILER_TAILCALL_TRASH;
698
- #endif // defined(_TARGET_AMD64_) || defined(_TARGET_X86_ )
740
+ #endif // defined(_TARGET_XARCH_ )
699
741
700
742
case CORINFO_HELP_ASSIGN_BYREF:
701
743
#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;
704
745
#elif defined(_TARGET_X86_)
705
746
// This helper only trashes ECX.
706
747
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_)
710
749
return RBM_CALLEE_TRASH_NOGC;
711
750
#endif // defined(_TARGET_AMD64_)
712
751
@@ -3912,16 +3951,86 @@ void CodeGen::genReportEH()
3912
3951
assert (XTnum == EHCount);
3913
3952
}
3914
3953
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)
3916
4025
{
3917
4026
#ifndef LEGACY_BACKEND
3918
4027
noway_assert (tgt->gtOper == GT_STOREIND);
3919
4028
#else // LEGACY_BACKEND
3920
4029
noway_assert (tgt->gtOper == GT_IND || tgt->gtOper == GT_CLS_VAR); // enforced by gcIsWriteBarrierCandidate
3921
4030
#endif // LEGACY_BACKEND
3922
4031
3923
- /* Call the proper vm helper */
3924
- int helper = CORINFO_HELP_ASSIGN_REF;
4032
+ CorInfoHelpFunc helper = CORINFO_HELP_ASSIGN_REF;
4033
+
3925
4034
#ifdef DEBUG
3926
4035
if (wbf == GCInfo::WBF_NoBarrier_CheckNotHeapInDebug)
3927
4036
{
@@ -3949,6 +4058,20 @@ void CodeGen::genGCWriteBarrier(GenTreePtr tgt, GCInfo::WriteBarrierForm wbf)
3949
4058
((helper == CORINFO_HELP_ASSIGN_REF) &&
3950
4059
(wbf == GCInfo::WBF_BarrierUnchecked || wbf == GCInfo::WBF_BarrierUnknown)));
3951
4060
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
+
3952
4075
#ifdef FEATURE_COUNT_GC_WRITE_BARRIERS
3953
4076
// We classify the "tgt" trees as follows:
3954
4077
// 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