Fix GC hole with multi-reg local var stores (#65916)
* Fix GC hole with multi-reg local var stores
Change #64857 exposed an existing problem where when generating code
for a multi-reg GT_STORE_LCL_VAR, if the first register slot was not
enregistered, but the second or subsequent slots was, and those non-first
slots contained GC pointers, we wouldn't properly add those GC pointers
to the GC tracking sets. This led to cases where the register lifetimes
would be killed in the GC info before the actual lifetime was complete.
The primary fix is to make `gtHasReg()` handle the `IsMultiRegLclVar()`
case. As a side-effect, this fixes some LSRA dumps that weren't displaying
multiple registers properly.
There are about 50 SPMI asm diffs on win-arm64 where register lifetimes
get extended, fixing GC holes.
I also made `GetMultiRegCount()` handle the `IsMultiRegLclVar()` case.
I made a number of cleanup changes along the way:
1. Fixed two cases of calling `gcInfo.gcMarkRegSetNpt` with regNumber, not regMaskTP
2. Marked some functions `const`
3. Improved some comments
4. Changed "ith" to "i'th" in comments which still doesn't read great,
but at least I'm not left trying to parse "ith" as an English word.
5. Use `OperIsScalarLocal()` more broadly
6. Renamed `gtDispRegCount` to `gtDispMultiRegCount` to make it clear
it only applies to the multi-reg case.
Fixes #65476.
* Update src/coreclr/jit/gentree.cpp
Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
Co-authored-by: Kunal Pathak <Kunal.Pathak@microsoft.com>
14 files changed: