}
}
+#ifdef _TARGET_ARM_
+//------------------------------------------------------------------------
+// addResolutionForDouble: Add resolution move(s) for TYP_DOUBLE interval
+// and update location.
+//
+// Arguments:
+// block - the BasicBlock into which the move will be inserted.
+// insertionPoint - the instruction before which to insert the move
+// sourceIntervals - maintains sourceIntervals[reg] which each 'reg' is associated with
+// location - maintains location[reg] which is the location of the var that was originally in 'reg'.
+// toReg - the register to which the var is moving
+// fromReg - the register from which the var is moving
+// resolveType - the type of resolution to be performed
+//
+// Return Value:
+// None.
+//
+// Notes:
+// It inserts at least one move and updates incoming parameter 'location'.
+//
+void LinearScan::addResolutionForDouble(BasicBlock* block,
+ GenTreePtr insertionPoint,
+ Interval** sourceIntervals,
+ regNumberSmall* location,
+ regNumber toReg,
+ regNumber fromReg,
+ ResolveType resolveType)
+{
+ regNumber secondHalfTargetReg = REG_NEXT(fromReg);
+ Interval* intervalToBeMoved1 = sourceIntervals[fromReg];
+ Interval* intervalToBeMoved2 = sourceIntervals[secondHalfTargetReg];
+
+ assert(!(intervalToBeMoved1 == nullptr && intervalToBeMoved2 == nullptr));
+
+ if (intervalToBeMoved1 != nullptr)
+ {
+ if (intervalToBeMoved1->registerType == TYP_DOUBLE)
+ {
+ // TYP_DOUBLE interval occupies a double register, i.e. two float registers.
+ assert(intervalToBeMoved2 == nullptr);
+ assert(genIsValidDoubleReg(toReg));
+ }
+ else
+ {
+ // TYP_FLOAT interval occupies 1st half of double register, i.e. 1st float register
+ assert(genIsValidFloatReg(toReg));
+ }
+ addResolution(block, insertionPoint, intervalToBeMoved1, toReg, fromReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[fromReg] = (regNumberSmall)toReg;
+ }
+
+ if (intervalToBeMoved2 != nullptr)
+ {
+ // TYP_FLOAT interval occupies 2nd half of double register.
+ assert(intervalToBeMoved2->registerType == TYP_FLOAT);
+ regNumber secondHalfTempReg = REG_NEXT(toReg);
+
+ addResolution(block, insertionPoint, intervalToBeMoved2, secondHalfTempReg, secondHalfTargetReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[secondHalfTargetReg] = (regNumberSmall)secondHalfTempReg;
+ }
+
+ return;
+}
+#endif // _TARGET_ARM_
+
//------------------------------------------------------------------------
// addResolution: Add a resolution move of the given interval
//
(resolveType == ResolveSharedCritical) ? REG_NA : getTempRegForResolution(fromBlock, toBlock, TYP_INT);
#endif // !_TARGET_XARCH_
regNumber tempRegFlt = REG_NA;
+ regNumber tempRegDbl = REG_NA; // Used only for ARM
if ((compiler->compFloatingPointUsed) && (resolveType != ResolveSharedCritical))
{
-
#ifdef _TARGET_ARM_
- // Let's try to reserve a double register for TYP_FLOAT and TYP_DOUBLE
- tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_DOUBLE);
- if (tempRegFlt == REG_NA)
+ // Try to reserve a double register for TYP_DOUBLE and use it for TYP_FLOAT too if available.
+ tempRegDbl = getTempRegForResolution(fromBlock, toBlock, TYP_DOUBLE);
+ if (tempRegDbl != REG_NA)
+ {
+ tempRegFlt = tempRegDbl;
+ }
+ else
+#endif // _TARGET_ARM_
{
- // If fails, try to reserve a float register for TYP_FLOAT
tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_FLOAT);
}
-#else
- tempRegFlt = getTempRegForResolution(fromBlock, toBlock, TYP_FLOAT);
-#endif
}
regMaskTP targetRegsToDo = RBM_NONE;
regNumber targetReg = genRegNumFromMask(targetRegMask);
if (location[targetReg] == REG_NA)
{
- targetRegsReady |= targetRegMask;
+#ifdef _TARGET_ARM_
+ regNumber sourceReg = (regNumber)source[targetReg];
+ Interval* interval = sourceIntervals[sourceReg];
+ if (interval->registerType == TYP_DOUBLE)
+ {
+ // For ARM32, make sure that both of the float halves of the double register are available.
+ assert(genIsValidDoubleReg(targetReg));
+ regNumber anotherHalfRegNum = REG_NEXT(targetReg);
+ if (location[anotherHalfRegNum] == REG_NA)
+ {
+ targetRegsReady |= targetRegMask;
+ }
+ }
+ else
+#endif // _TARGET_ARM_
+ {
+ targetRegsReady |= targetRegMask;
+ }
}
}
if (sourceIntervals[fromReg]->registerType == TYP_DOUBLE)
{
// ARM32 requires a double temp register for TYP_DOUBLE.
- // We tried to reserve a double temp register first, but sometimes we can't.
- tempReg = genIsValidDoubleReg(tempRegFlt) ? tempRegFlt : REG_NA;
+ tempReg = tempRegDbl;
}
else
#endif // _TARGET_ARM_
else
{
compiler->codeGen->regSet.rsSetRegsModified(genRegMask(tempReg) DEBUGARG(dumpTerse));
- assert(sourceIntervals[targetReg] != nullptr);
- addResolution(block, insertionPoint, sourceIntervals[targetReg], tempReg, targetReg);
- JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
- location[targetReg] = (regNumberSmall)tempReg;
+#ifdef _TARGET_ARM_
+ if (sourceIntervals[fromReg]->registerType == TYP_DOUBLE)
+ {
+ assert(genIsValidDoubleReg(targetReg));
+ assert(genIsValidDoubleReg(tempReg));
+
+ addResolutionForDouble(block, insertionPoint, sourceIntervals, location, tempReg, targetReg,
+ resolveType);
+ }
+ else
+#endif // _TARGET_ARM_
+ {
+ assert(sourceIntervals[targetReg] != nullptr);
+
+ addResolution(block, insertionPoint, sourceIntervals[targetReg], tempReg, targetReg);
+ JITDUMP(" (%s)\n", resolveTypeName[resolveType]);
+ location[targetReg] = (regNumberSmall)tempReg;
+ }
targetRegsReady |= targetRegMask;
}
}