diff --git a/src/coreclr/jit/lsra.cpp b/src/coreclr/jit/lsra.cpp index be55b9c75d2b20..f53f77c8e46c17 100644 --- a/src/coreclr/jit/lsra.cpp +++ b/src/coreclr/jit/lsra.cpp @@ -12985,8 +12985,69 @@ void LinearScan::RegisterSelection::try_REG_ORDER() // This will always result in a single candidate. That is, it is the tie-breaker // for free candidates, and doesn't make sense as anything other than the last // heuristic for free registers. - unsigned lowestRegOrder = UINT_MAX; - SingleTypeRegSet lowestRegOrderBit = RBM_NONE; +#ifdef TARGET_ARM64 + // These groups preserve REG_VAR_ORDER and REG_VAR_ORDER_FLT. Select from + // the first nonempty group instead of visiting every candidate's rank. + SingleTypeRegSet preferred; + SingleTypeRegSet lowestRegOrderBit; + if (varTypeUsesFloatReg(regType)) + { + // Mask off V0-V15 to select the V16-V31 group. + preferred = candidates & (RBM_ALLFLOAT.GetFloatRegSet() & ~((1ULL << REG_V16) - 1)); + if (preferred != RBM_NONE) + { + lowestRegOrderBit = genFindLowestBit(preferred); + } + else + { + preferred = candidates & (RBM_V4 | RBM_V5 | RBM_V6 | RBM_V7).GetFloatRegSet(); + if (preferred != RBM_NONE) + { + // V7..V4 are preferred in descending register-number order. + lowestRegOrderBit = 1ULL << BitOperations::BitScanReverse(preferred); + } + else + { + preferred = + candidates & + (RBM_V8 | RBM_V9 | RBM_V10 | RBM_V11 | RBM_V12 | RBM_V13 | RBM_V14 | RBM_V15).GetFloatRegSet(); + if (preferred != RBM_NONE) + { + lowestRegOrderBit = genFindLowestBit(preferred); + } + else + { + // The remaining floating-point registers are V3..V0. + lowestRegOrderBit = 1ULL << BitOperations::BitScanReverse(candidates); + } + } + } + } + else if (varTypeIsMask(regType)) + { + // ARM64 predicate registers have equal regOrder ranks. + lowestRegOrderBit = genFindLowestBit(candidates); + } + else + { + preferred = candidates & (((1ULL << REG_R12) - 1) | (RBM_R13 | RBM_R14).GetIntRegSet()); + if (preferred == RBM_NONE) + { + // After R13/R14, the remaining ranked registers are in ascending order. + preferred = candidates & RBM_ALLINT.GetIntRegSet(); + if (preferred == RBM_NONE) + { + // Registers absent from REG_VAR_ORDER retain the same last rank. + preferred = candidates; + } + } + lowestRegOrderBit = genFindLowestBit(preferred); + } +#endif // TARGET_ARM64 + +#if !defined(TARGET_ARM64) || defined(DEBUG) + unsigned lowestRegOrder = UINT_MAX; + regNumber lowestReg = REG_NA; for (SingleTypeRegSet regOrderCandidates = candidates; regOrderCandidates != RBM_NONE;) { regNumber regOrderCandidateRegNum = genFirstRegNumFromMask(regOrderCandidates, regType); @@ -12996,10 +13057,19 @@ void LinearScan::RegisterSelection::try_REG_ORDER() unsigned thisRegOrder = linearScan->getRegisterRecord(regOrderCandidateRegNum)->regOrder; if (thisRegOrder < lowestRegOrder) { - lowestRegOrder = thisRegOrder; - lowestRegOrderBit = regOrderCandidateBit; + lowestRegOrder = thisRegOrder; + lowestReg = regOrderCandidateRegNum; } } + assert(lowestReg != REG_NA); + SingleTypeRegSet scannedRegOrderBit = genSingleTypeRegMask(lowestReg); +#ifdef TARGET_ARM64 + // Check the grouped selection against the rank scan, including stress modes. + assert(lowestRegOrderBit == scannedRegOrderBit); +#else + SingleTypeRegSet lowestRegOrderBit = scannedRegOrderBit; +#endif +#endif // !TARGET_ARM64 || DEBUG assert(lowestRegOrderBit != RBM_NONE); found = applySingleRegSelection(REG_ORDER, lowestRegOrderBit); }