diff options
author | Kunal Pathak <Kunal.Pathak@microsoft.com> | 2021-06-14 23:29:15 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-06-14 23:29:15 +0300 |
commit | cc9fdadb9aa9bec7eb45c9cf62563259b00bc55e (patch) | |
tree | c5dcbc819881c31749be7dc981e4e0230b8e15f6 /src/coreclr/jit/lsraarm64.cpp | |
parent | d95bfea59ed7d19e9b1db096c9d332005989296b (diff) |
Do not mark op2 as delayRegFree if op1==op2 (#53964)
* Do not mark op2 as delayRegFree if op1==op2
* Revert NodesAreEquivalentLeaves change
* Pass rmwNode to `BuildDelayFreeUses()` which does the right thing
* Make similar change in arm64
* remove TODO comment
* review feedback
Diffstat (limited to 'src/coreclr/jit/lsraarm64.cpp')
-rw-r--r-- | src/coreclr/jit/lsraarm64.cpp | 60 |
1 files changed, 12 insertions, 48 deletions
diff --git a/src/coreclr/jit/lsraarm64.cpp b/src/coreclr/jit/lsraarm64.cpp index 223dc906bad..a7a14fdfe54 100644 --- a/src/coreclr/jit/lsraarm64.cpp +++ b/src/coreclr/jit/lsraarm64.cpp @@ -1112,54 +1112,11 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) // RMW intrinsic operands doesn't have to be delayFree when they can be assigned the same register as op1Reg // (i.e. a register that corresponds to read-modify-write operand) and one of them is the last use. - bool op2DelayFree = isRMW; - bool op3DelayFree = isRMW; - bool op4DelayFree = isRMW; - assert(intrin.op1 != nullptr); - if (isRMW && intrin.op1->OperIs(GT_LCL_VAR)) - { - unsigned int varNum1 = intrin.op1->AsLclVar()->GetLclNum(); - bool op1LastUse = false; - - unsigned int varNum2 = BAD_VAR_NUM; - unsigned int varNum3 = BAD_VAR_NUM; - unsigned int varNum4 = BAD_VAR_NUM; - - if (intrin.op2->OperIs(GT_LCL_VAR)) - { - varNum2 = intrin.op2->AsLclVar()->GetLclNum(); - op1LastUse |= ((varNum1 == varNum2) && intrin.op2->HasLastUse()); - } - - if (intrin.op3 != nullptr) - { - if (intrin.op3->OperIs(GT_LCL_VAR)) - { - varNum3 = intrin.op3->AsLclVar()->GetLclNum(); - op1LastUse |= ((varNum1 == varNum3) && intrin.op3->HasLastUse()); - } - - if ((intrin.op4 != nullptr) && intrin.op4->OperIs(GT_LCL_VAR)) - { - varNum4 = intrin.op4->AsLclVar()->GetLclNum(); - op1LastUse |= ((varNum1 == varNum4) && intrin.op4->HasLastUse()); - } - } - - if (op1LastUse) - { - op2DelayFree = (varNum1 != varNum2); - op3DelayFree = (varNum1 != varNum3); - op4DelayFree = (varNum1 != varNum4); - } - } - + bool forceOp2DelayFree = false; if ((intrin.id == NI_Vector64_GetElement) || (intrin.id == NI_Vector128_GetElement)) { - assert(!op2DelayFree); - if (!intrin.op2->IsCnsIntOrI() && (!intrin.op1->isContained() || intrin.op1->OperIsLocal())) { // If the index is not a constant and the object is not contained or is a local @@ -1168,7 +1125,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) // TODO-Cleanup: An internal register will never clobber a source; this code actually // ensures that the index (op2) doesn't interfere with the target. buildInternalIntRegisterDefForNode(intrinsicTree); - op2DelayFree = true; + forceOp2DelayFree = true; } if (!intrin.op2->IsCnsIntOrI() && !intrin.op1->isContained()) @@ -1179,15 +1136,22 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree) } } - srcCount += op2DelayFree ? BuildDelayFreeUses(intrin.op2) : BuildOperandUses(intrin.op2); + if (forceOp2DelayFree) + { + srcCount += BuildDelayFreeUses(intrin.op2); + } + else + { + srcCount += isRMW ? BuildDelayFreeUses(intrin.op2, intrin.op1) : BuildOperandUses(intrin.op2); + } if (intrin.op3 != nullptr) { - srcCount += op3DelayFree ? BuildDelayFreeUses(intrin.op3) : BuildOperandUses(intrin.op3); + srcCount += isRMW ? BuildDelayFreeUses(intrin.op3, intrin.op1) : BuildOperandUses(intrin.op3); if (intrin.op4 != nullptr) { - srcCount += op4DelayFree ? BuildDelayFreeUses(intrin.op4) : BuildOperandUses(intrin.op4); + srcCount += isRMW ? BuildDelayFreeUses(intrin.op4, intrin.op1) : BuildOperandUses(intrin.op4); } } } |