From 6372cb61696d81b0374f7c279ee2ee8c29c0c154 Mon Sep 17 00:00:00 2001 From: Deepak Rajendrakumaran Date: Thu, 24 Jul 2025 15:46:37 -0700 Subject: [PATCH 1/3] Prevent eGPRs from being used as GC tracked regs. --- src/coreclr/jit/lsra.cpp | 34 ++++++++++++++++++++++++++++++++-- src/coreclr/jit/lsra.h | 3 ++- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 22dea851621b87..d2f9ab35bbdafd 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -498,6 +498,35 @@ RegRecord* LinearScan::getRegisterRecord(regNumber regNum) return &physRegs[regNum]; } +//------------------------------------------------------------------------ +// getAvailableGPRsForType: Returns available general-purpose registers for the given type, +// with platform-specific restrictions applied. +// +// Arguments: +// candidates - The candidate register mask to be filtered +// regType - The register type for which we need available registers +// +// Return Value: +// A filtered register mask with platform-specific restrictions applied. +// For AMD64: GC types and long types are restricted to low GPRs only. +// For other platforms: Returns the original candidates unchanged. +// +// Notes: +// On AMD64, we don't use extended GPRs (R16-R31) for GC types to ensure +// proper GC tracking and code generation compatibility. +// +SingleTypeRegSet LinearScan::getAvailableGPRsForType(SingleTypeRegSet candidates, var_types regType) +{ +#ifdef TARGET_AMD64 + if ((varTypeIsGC(regType) || varTypeIsLong(regType)) && ((candidates & RBM_LOWINT.getLow()) != 0)) + { + // For AMD64, we don't use eGPR for GC types. + candidates &= (SingleTypeRegSet)RBM_LOWINT.getLow(); + } +#endif // TARGET_AMD64 + return candidates; +} + #ifdef DEBUG //---------------------------------------------------------------------------- @@ -8694,6 +8723,7 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, } #else // !TARGET_ARM SingleTypeRegSet freeRegs = allRegs(type); + freeRegs = getAvailableGPRsForType(freeRegs, (type == TYP_INT) ? TYP_REF : type); #endif // !TARGET_ARM #ifdef DEBUG @@ -13466,7 +13496,7 @@ SingleTypeRegSet LinearScan::RegisterSelection::select(Interval* { preferences = candidates; } - + candidates = linearScan->getAvailableGPRsForType(candidates, regType); #ifdef DEBUG candidates = linearScan->stressLimitRegs(refPosition, regType, candidates); #endif @@ -13934,7 +13964,7 @@ SingleTypeRegSet LinearScan::RegisterSelection::selectMinimal( } } } - + candidates = linearScan->getAvailableGPRsForType(candidates, regType); #ifdef DEBUG candidates = linearScan->stressLimitRegs(refPosition, regType, candidates); #endif diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index e8484bed8e3d6a..7d00e272ed6377 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -1142,7 +1142,8 @@ class LinearScan : public LinearScanInterface return getIntervalForLocalVar(varDsc->lvVarIndex); } - RegRecord* getRegisterRecord(regNumber regNum); + RegRecord* getRegisterRecord(regNumber regNum); + SingleTypeRegSet getAvailableGPRsForType(SingleTypeRegSet candidates, var_types regType); RefPosition* newRefPositionRaw(LsraLocation nodeLocation, GenTree* treeNode, RefType refType); From 222da0dd1793ba13bc168add1b356291aaf7fa89 Mon Sep 17 00:00:00 2001 From: Deepak Rajendrakumaran Date: Fri, 25 Jul 2025 02:57:18 -0700 Subject: [PATCH 2/3] Addressing review comments. --- src/coreclr/jit/lsra.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index d2f9ab35bbdafd..9a0fb03a47eaa9 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -518,7 +518,7 @@ RegRecord* LinearScan::getRegisterRecord(regNumber regNum) SingleTypeRegSet LinearScan::getAvailableGPRsForType(SingleTypeRegSet candidates, var_types regType) { #ifdef TARGET_AMD64 - if ((varTypeIsGC(regType) || varTypeIsLong(regType)) && ((candidates & RBM_LOWINT.getLow()) != 0)) + if (varTypeIsGC(regType) || varTypeIsLong(regType)) { // For AMD64, we don't use eGPR for GC types. candidates &= (SingleTypeRegSet)RBM_LOWINT.getLow(); @@ -8723,6 +8723,8 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, } #else // !TARGET_ARM SingleTypeRegSet freeRegs = allRegs(type); + // We call this method with only either TYP_INT or TYP_FLOAT. + // We are being conservative with eGPR usage when type is TYP_INT since it could be a reference type. freeRegs = getAvailableGPRsForType(freeRegs, (type == TYP_INT) ? TYP_REF : type); #endif // !TARGET_ARM From 3103e189a9fed3ddc62cc164c75ba9aac7e1fb9e Mon Sep 17 00:00:00 2001 From: Deepak Rajendrakumaran Date: Fri, 25 Jul 2025 03:19:02 -0700 Subject: [PATCH 3/3] Fix formatting --- src/coreclr/jit/lsra.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index 9a0fb03a47eaa9..787a93c5721256 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -8723,9 +8723,9 @@ regNumber LinearScan::getTempRegForResolution(BasicBlock* fromBlock, } #else // !TARGET_ARM SingleTypeRegSet freeRegs = allRegs(type); - // We call this method with only either TYP_INT or TYP_FLOAT. + // We call getTempRegForResolution() with only either TYP_INT or TYP_FLOAT. // We are being conservative with eGPR usage when type is TYP_INT since it could be a reference type. - freeRegs = getAvailableGPRsForType(freeRegs, (type == TYP_INT) ? TYP_REF : type); + freeRegs = getAvailableGPRsForType(freeRegs, (type == TYP_INT) ? TYP_REF : type); #endif // !TARGET_ARM #ifdef DEBUG