From fcf3dff9fcb75d0e04c2fab0d7347321adbe59bf Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Tue, 27 Oct 2026 09:23:05 +0000 Subject: [PATCH] ARM64: Select REG_ORDER candidates with ordered masks - Related to #136694 Use register-mask groups in ARM64 register allocation to preserve the existing register preference order without scanning every candidate's rank. Keep the original scan on other targets and cross-check choices in Checked builds. Against main (b4548da6edfc), Release JITs executed 3,999,913,819,224 instructions versus 4,017,017,735,574 on main across seven published Linux ARM64 SuperPMI collections, a 0.426% reduction. SuperPMI asm diffs found no generated code differences among replayed contexts. --- src/coreclr/jit/lsra.cpp | 78 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 74 insertions(+), 4 deletions(-) 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); }