Lock the the dest reg in `inst_RV_TT` if necessary.
authorPat Gavlin <pagavlin@microsoft.com>
Fri, 21 Jul 2017 23:43:25 +0000 (16:43 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Fri, 21 Jul 2017 23:43:25 +0000 (16:43 -0700)
For ARM32, `inst_RV_TT` may need to load the referenced lclVar into a
temporary register before emitting the requested instruction. The
chosen register *must not* be the instruction's destination register.
The existing code attempted to ensure this by masking the dest register
from the set of pickable registers, but this is not sufficient:
`rsPickReg` must return a valid register and will happily attempt to
spill and return the destination register even if it is not in the
recommended set. To prevent this, this change locks and unlocks the
destination register if necessary (i.e. if it was not locked upon
entry).

Fixes #12935.

src/jit/instr.cpp

index c4e894b..2b9780f 100644 (file)
@@ -2532,7 +2532,24 @@ AGAIN:
                     }
                     else
                     {
-                        regTmp = regSet.rsPickReg(RBM_ALLINT & ~genRegMask(reg));
+                        // Lock the destination register to ensure that rsPickReg does not choose it.
+                        const regMaskTP regMask = genRegMask(reg);
+                        if ((regMask & regSet.rsMaskUsed) == 0)
+                        {
+                            regSet.rsLockReg(regMask);
+                            regTmp = regSet.rsPickReg(RBM_ALLINT);
+                            regSet.rsUnlockReg(regMask);
+                        }
+                        else if ((regMask & regSet.rsMaskLock) == 0)
+                        {
+                            regSet.rsLockUsedReg(regMask);
+                            regTmp = regSet.rsPickReg(RBM_ALLINT);
+                            regSet.rsUnlockUsedReg(regMask);
+                        }
+                        else
+                        {
+                            regTmp = regSet.rsPickReg(RBM_ALLINT);
+                        }
                     }
 #endif // LEGACY_BACKEND