summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHanjoung Lee <hanjoung.lee@samsung.com>2017-08-01 11:45:17 +0900
committerHanjoung Lee <hanjoung.lee@samsung.com>2017-08-07 11:37:02 +0900
commit0e0e60d758ac330e873d901c53672411961ac5c5 (patch)
treebe3a5a6b401b92cf5ecfff01c581aea3f4f0058c /src
parente5b4c7b611414e189b967254914c84aad46fd1ad (diff)
downloadcoreclr-0e0e60d758ac330e873d901c53672411961ac5c5.tar.gz
coreclr-0e0e60d758ac330e873d901c53672411961ac5c5.tar.bz2
coreclr-0e0e60d758ac330e873d901c53672411961ac5c5.zip
[RyuJIT/armel] Each reg gets own SpillFlag for MultiRegOp
Diffstat (limited to 'src')
-rw-r--r--src/jit/codegenlinear.cpp42
-rw-r--r--src/jit/gentree.h131
-rw-r--r--src/jit/lsra.cpp7
-rw-r--r--src/jit/regset.cpp26
4 files changed, 204 insertions, 2 deletions
diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp
index 59d08de9ce..dfe0458c51 100644
--- a/src/jit/codegenlinear.cpp
+++ b/src/jit/codegenlinear.cpp
@@ -1034,6 +1034,32 @@ void CodeGen::genUnspillRegIfNeeded(GenTree* tree)
unspillTree->gtFlags &= ~GTF_SPILLED;
}
+ else if (unspillTree->OperIsMultiRegOp())
+ {
+ GenTreeMultiRegOp* multiReg = unspillTree->AsMultiRegOp();
+ unsigned regCount = multiReg->gtOtherReg == REG_NA ? 1 : 2;
+
+ // In case of split struct argument node, GTF_SPILLED flag on it indicates that
+ // one or more of its result regs are spilled. Call node needs to be
+ // queried to know which specific result regs to be unspilled.
+ for (unsigned i = 0; i < regCount; ++i)
+ {
+ unsigned flags = multiReg->GetRegSpillFlagByIdx(i);
+ if ((flags & GTF_SPILLED) != 0)
+ {
+ var_types dstType = multiReg->GetRegType(i);
+ regNumber dstReg = multiReg->GetRegNumByIdx(i);
+
+ TempDsc* t = regSet.rsUnspillInPlace(multiReg, dstReg, i);
+ getEmitter()->emitIns_R_S(ins_Load(dstType), emitActualTypeSize(dstType), dstReg, t->tdTempNum(),
+ 0);
+ compiler->tmpRlsTemp(t);
+ gcInfo.gcMarkRegPtrVal(dstReg, dstType);
+ }
+ }
+
+ unspillTree->gtFlags &= ~GTF_SPILLED;
+ }
#endif
else
{
@@ -1656,6 +1682,22 @@ void CodeGen::genProduceReg(GenTree* tree)
}
}
}
+ else if (tree->OperIsMultiRegOp())
+ {
+ GenTreeMultiRegOp* multiReg = tree->AsMultiRegOp();
+ unsigned regCount = multiReg->gtOtherReg == REG_NA ? 1 : 2;
+
+ for (unsigned i = 0; i < regCount; ++i)
+ {
+ unsigned flags = multiReg->GetRegSpillFlagByIdx(i);
+ if ((flags & GTF_SPILL) != 0)
+ {
+ regNumber reg = multiReg->GetRegNumByIdx(i);
+ regSet.rsSpillTree(reg, multiReg, i);
+ gcInfo.gcMarkRegSetNpt(genRegMask(reg));
+ }
+ }
+ }
#endif // _TARGET_ARM_
else
{
diff --git a/src/jit/gentree.h b/src/jit/gentree.h
index 365dca6b7b..54545aa896 100644
--- a/src/jit/gentree.h
+++ b/src/jit/gentree.h
@@ -1333,6 +1333,18 @@ public:
return OperIsPutArgStk() || OperIsPutArgReg() || OperIsPutArgSplit();
}
+ bool OperIsMultiRegOp() const
+ {
+#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
+ if (gtOper == GT_MUL_LONG || gtOper == GT_PUTARG_REG || gtOper == GT_COPY)
+ {
+ return true;
+ }
+#endif
+
+ return false;
+ }
+
bool OperIsAddrMode() const
{
return OperIsAddrMode(OperGet());
@@ -3894,9 +3906,128 @@ struct GenTreeMultiRegOp : public GenTreeOp
{
regNumber gtOtherReg;
+ // GTF_SPILL or GTF_SPILLED flag on a multi-reg call node indicates that one or
+ // more of its result regs are in that state. The spill flag of each of the
+ // return register is stored here. We only need 2 bits per returned register,
+ // so this is treated as a 2-bit array. No architecture needs more than 8 bits.
+
+ static const unsigned PACKED_GTF_SPILL = 1;
+ static const unsigned PACKED_GTF_SPILLED = 2;
+ unsigned char gtSpillFlags;
+
GenTreeMultiRegOp(genTreeOps oper, var_types type, GenTreePtr op1, GenTreePtr op2)
: GenTreeOp(oper, type, op1, op2), gtOtherReg(REG_NA)
{
+ ClearOtherRegFlags();
+ }
+
+ //---------------------------------------------------------------------------
+ // GetRegNumByIdx: get ith register allocated to this struct argument.
+ //
+ // Arguments:
+ // idx - index of the register
+ //
+ // Return Value:
+ // Return regNumber of ith register of this register argument
+ //
+ regNumber GetRegNumByIdx(unsigned idx) const
+ {
+ assert(idx < 2);
+
+ if (idx == 0)
+ {
+ return gtRegNum;
+ }
+
+ return gtOtherReg;
+ }
+
+ //----------------------------------------------------------------------
+ // GetRegSpillFlagByIdx: get spill flag associated with the register
+ // specified by its index.
+ //
+ // Arguments:
+ // idx - Position or index of the register
+ //
+ // Return Value:
+ // Returns GTF_* flags associated with the register. Only GTF_SPILL and GTF_SPILLED are considered.
+ //
+ unsigned GetRegSpillFlagByIdx(unsigned idx) const
+ {
+ assert(idx < MAX_REG_ARG);
+
+ unsigned bits = gtSpillFlags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here.
+ unsigned spillFlags = 0;
+ if (bits & PACKED_GTF_SPILL)
+ {
+ spillFlags |= GTF_SPILL;
+ }
+ if (bits & PACKED_GTF_SPILLED)
+ {
+ spillFlags |= GTF_SPILLED;
+ }
+
+ return spillFlags;
+ }
+
+ //----------------------------------------------------------------------
+ // SetRegSpillFlagByIdx: set spill flags for the register
+ // specified by its index.
+ //
+ // Arguments:
+ // flags - GTF_* flags. Only GTF_SPILL and GTF_SPILLED are allowed.
+ // idx - Position or index of the register
+ //
+ // Return Value:
+ // None
+ //
+ void SetRegSpillFlagByIdx(unsigned flags, unsigned idx)
+ {
+ assert(idx < MAX_REG_ARG);
+
+ unsigned bits = 0;
+ if (flags & GTF_SPILL)
+ {
+ bits |= PACKED_GTF_SPILL;
+ }
+ if (flags & GTF_SPILLED)
+ {
+ bits |= PACKED_GTF_SPILLED;
+ }
+
+ // Clear anything that was already there by masking out the bits before 'or'ing in what we want there.
+ gtSpillFlags = (unsigned char)((gtSpillFlags & ~(0xffU << (idx * 2))) | (bits << (idx * 2)));
+ }
+
+ //--------------------------------------------------------------------------
+ // GetRegType: Get var_type of the register specified by index.
+ //
+ // Arguments:
+ // index - Index of the register.
+ // First register will have an index 0 and so on.
+ //
+ // Return Value:
+ // var_type of the register specified by its index.
+
+ var_types GetRegType(unsigned index)
+ {
+ assert(index < 2);
+ var_types result = TYP_INT; // XXX
+ return result;
+ }
+
+ //-------------------------------------------------------------------
+ // clearOtherRegFlags: clear GTF_* flags associated with gtOtherRegs
+ //
+ // Arguments:
+ // None
+ //
+ // Return Value:
+ // None
+ //
+ void ClearOtherRegFlags()
+ {
+ gtSpillFlags = 0;
}
#if DEBUGGABLE_GENTREE
diff --git a/src/jit/lsra.cpp b/src/jit/lsra.cpp
index 691865df9b..e5c62fd344 100644
--- a/src/jit/lsra.cpp
+++ b/src/jit/lsra.cpp
@@ -3987,7 +3987,7 @@ void LinearScan::buildRefPositionsForNode(GenTree* tree,
regMaskTP candidates = getUseCandidates(useNode);
#ifdef ARM_SOFTFP
// If oper is GT_PUTARG_REG, set bits in useCandidates must be in sequential order.
- if (useNode->OperGet() == GT_PUTARG_REG || useNode->OperGet() == GT_COPY)
+ if (useNode->OperIsMultiRegOp())
{
regMaskTP candidate = genFindLowestReg(candidates);
useNode->gtLsraInfo.setSrcCandidates(this, candidates & ~candidate);
@@ -9239,6 +9239,11 @@ void LinearScan::resolveRegisters()
GenTreePutArgSplit* splitArg = treeNode->AsPutArgSplit();
splitArg->SetRegSpillFlagByIdx(GTF_SPILL, currentRefPosition->getMultiRegIdx());
}
+ else if (treeNode->OperIsMultiRegOp())
+ {
+ GenTreeMultiRegOp* multiReg = treeNode->AsMultiRegOp();
+ multiReg->SetRegSpillFlagByIdx(GTF_SPILL, currentRefPosition->getMultiRegIdx());
+ }
#endif
}
diff --git a/src/jit/regset.cpp b/src/jit/regset.cpp
index 6c1a98d077..e73b64598f 100644
--- a/src/jit/regset.cpp
+++ b/src/jit/regset.cpp
@@ -1533,6 +1533,7 @@ void RegSet::rsSpillTree(regNumber reg, GenTreePtr tree, unsigned regIdx /* =0 *
var_types treeType;
#if !defined(LEGACY_BACKEND) && defined(_TARGET_ARM_)
GenTreePutArgSplit* splitArg = nullptr;
+ GenTreeMultiRegOp* multiReg = nullptr;
#endif
#ifndef LEGACY_BACKEND
@@ -1548,6 +1549,11 @@ void RegSet::rsSpillTree(regNumber reg, GenTreePtr tree, unsigned regIdx /* =0 *
splitArg = tree->AsPutArgSplit();
treeType = splitArg->GetRegType(regIdx);
}
+ else if (tree->OperIsMultiRegOp())
+ {
+ multiReg = tree->AsMultiRegOp();
+ treeType = multiReg->GetRegType(regIdx); // XXX check
+ }
#endif // _TARGET_ARM_
else
#endif // !LEGACY_BACKEND
@@ -1605,10 +1611,16 @@ void RegSet::rsSpillTree(regNumber reg, GenTreePtr tree, unsigned regIdx /* =0 *
assert((regFlags & GTF_SPILL) != 0);
regFlags &= ~GTF_SPILL;
}
+ else if (multiReg != nullptr)
+ {
+ regFlags = multiReg->GetRegSpillFlagByIdx(regIdx);
+ assert((regFlags & GTF_SPILL) != 0);
+ regFlags &= ~GTF_SPILL;
+ }
#endif // _TARGET_ARM_
else
{
- assert(!varTypeIsMultiReg(tree) || (m_rsCompiler->opts.compUseSoftFP && treeType == TYP_LONG));
+ assert(!varTypeIsMultiReg(tree));
tree->gtFlags &= ~GTF_SPILL;
}
#endif // !LEGACY_BACKEND
@@ -1759,6 +1771,11 @@ void RegSet::rsSpillTree(regNumber reg, GenTreePtr tree, unsigned regIdx /* =0 *
regFlags |= GTF_SPILLED;
splitArg->SetRegSpillFlagByIdx(regFlags, regIdx);
}
+ else if (multiReg != nullptr)
+ {
+ regFlags |= GTF_SPILLED;
+ multiReg->SetRegSpillFlagByIdx(regFlags, regIdx);
+ }
#endif // _TARGET_ARM_
#endif //! LEGACY_BACKEND
}
@@ -2401,6 +2418,13 @@ TempDsc* RegSet::rsUnspillInPlace(GenTreePtr tree, regNumber oldReg, unsigned re
flags &= ~GTF_SPILLED;
splitArg->SetRegSpillFlagByIdx(flags, regIdx);
}
+ else if (tree->OperIsMultiRegOp())
+ {
+ GenTreeMultiRegOp* multiReg = tree->AsMultiRegOp();
+ unsigned flags = multiReg->GetRegSpillFlagByIdx(regIdx);
+ flags &= ~GTF_SPILLED;
+ multiReg->SetRegSpillFlagByIdx(flags, regIdx);
+ }
#endif // !LEGACY_BACKEND && _TARGET_ARM_
else
{