diff options
author | Hanjoung Lee <hanjoung.lee@samsung.com> | 2017-08-01 11:45:17 +0900 |
---|---|---|
committer | Hanjoung Lee <hanjoung.lee@samsung.com> | 2017-08-07 11:37:02 +0900 |
commit | 0e0e60d758ac330e873d901c53672411961ac5c5 (patch) | |
tree | be3a5a6b401b92cf5ecfff01c581aea3f4f0058c /src | |
parent | e5b4c7b611414e189b967254914c84aad46fd1ad (diff) | |
download | coreclr-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.cpp | 42 | ||||
-rw-r--r-- | src/jit/gentree.h | 131 | ||||
-rw-r--r-- | src/jit/lsra.cpp | 7 | ||||
-rw-r--r-- | src/jit/regset.cpp | 26 |
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 { |