summaryrefslogtreecommitdiff
path: root/src/jit/rationalize.cpp
diff options
context:
space:
mode:
authorCarol Eidt <carol.eidt@microsoft.com>2016-11-09 09:09:49 -0800
committerCarol Eidt <carol.eidt@microsoft.com>2016-11-18 15:32:24 -0800
commitaa676e8b01b29942e82c58011b0e183f923ff2bc (patch)
tree7b5cc4342c35545c2de6d4c5374fd0b3d06b8a72 /src/jit/rationalize.cpp
parentf4b527dfb2ed02e268e4f1d5318fa79053ede064 (diff)
downloadcoreclr-aa676e8b01b29942e82c58011b0e183f923ff2bc.tar.gz
coreclr-aa676e8b01b29942e82c58011b0e183f923ff2bc.tar.bz2
coreclr-aa676e8b01b29942e82c58011b0e183f923ff2bc.zip
Reinstate the struct optimization changes:
Remove many of the restrictions on structs that were added to preserve behavior of the old IR form. Change the init block representation to not require changing the parent when a copy block is changed to an init. In addition, fix the bug that was causing the corefx ValueTuple tests to fail. This was a bug in assertion prop where it was not invaliding the assertions about the parent struct when a field is modified. Add a repro test case for that bug. Incorporate the fix to #7954, which was encountered after the earlier version of these changes. This was a case where we reused a struct temp, and then it wound up eventually getting assigned the value it originally contained, so we had V09 = V09. This hit the assert in liveness where it wasn't expecting to find a struct assignment with the same lclVar on the lhs and rhs. This assert should have been eliminated with the IR change to struct assignments, but when this situation arises we may run into issues if we call a helper that doesn't expect the lhs and rhs to be the same. So, change morph to eliminate such assignments.
Diffstat (limited to 'src/jit/rationalize.cpp')
-rw-r--r--src/jit/rationalize.cpp84
1 files changed, 64 insertions, 20 deletions
diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp
index c552474752..873c608ce4 100644
--- a/src/jit/rationalize.cpp
+++ b/src/jit/rationalize.cpp
@@ -441,33 +441,77 @@ void Rationalizer::RewriteAssignment(LIR::Use& use)
genTreeOps locationOp = location->OperGet();
-#ifdef FEATURE_SIMD
- if (varTypeIsSIMD(location) && assignment->OperIsInitBlkOp())
+ if (assignment->OperIsBlkOp())
{
- if (location->OperGet() == GT_LCL_VAR)
+#ifdef FEATURE_SIMD
+ if (varTypeIsSIMD(location) && assignment->OperIsInitBlkOp())
{
- var_types simdType = location->TypeGet();
- GenTree* initVal = assignment->gtOp.gtOp2;
- var_types baseType = comp->getBaseTypeOfSIMDLocal(location);
- if (baseType != TYP_UNKNOWN)
+ if (location->OperGet() == GT_LCL_VAR)
{
- GenTreeSIMD* simdTree = new (comp, GT_SIMD)
- GenTreeSIMD(simdType, initVal, SIMDIntrinsicInit, baseType, genTypeSize(simdType));
- assignment->gtOp.gtOp2 = simdTree;
- value = simdTree;
- initVal->gtNext = simdTree;
- simdTree->gtPrev = initVal;
-
- simdTree->gtNext = location;
- location->gtPrev = simdTree;
+ var_types simdType = location->TypeGet();
+ GenTree* initVal = assignment->gtOp.gtOp2;
+ var_types baseType = comp->getBaseTypeOfSIMDLocal(location);
+ if (baseType != TYP_UNKNOWN)
+ {
+ GenTreeSIMD* simdTree = new (comp, GT_SIMD)
+ GenTreeSIMD(simdType, initVal, SIMDIntrinsicInit, baseType, genTypeSize(simdType));
+ assignment->gtOp.gtOp2 = simdTree;
+ value = simdTree;
+ initVal->gtNext = simdTree;
+ simdTree->gtPrev = initVal;
+
+ simdTree->gtNext = location;
+ location->gtPrev = simdTree;
+ }
}
}
- else
+#endif // FEATURE_SIMD
+ if ((location->TypeGet() == TYP_STRUCT) && !assignment->IsPhiDefn() && !value->IsMultiRegCall())
{
- assert(location->OperIsBlk());
+ if ((location->OperGet() == GT_LCL_VAR))
+ {
+ // We need to construct a block node for the location.
+ // Modify lcl to be the address form.
+ location->SetOper(addrForm(locationOp));
+ LclVarDsc* varDsc = &(comp->lvaTable[location->AsLclVarCommon()->gtLclNum]);
+ location->gtType = TYP_BYREF;
+ GenTreeBlk* storeBlk = nullptr;
+ unsigned int size = varDsc->lvExactSize;
+
+ if (varDsc->lvStructGcCount != 0)
+ {
+ CORINFO_CLASS_HANDLE structHnd = varDsc->lvVerTypeInfo.GetClassHandle();
+ GenTreeObj* objNode = comp->gtNewObjNode(structHnd, location)->AsObj();
+ unsigned int slots = (unsigned)(roundUp(size, TARGET_POINTER_SIZE) / TARGET_POINTER_SIZE);
+
+ objNode->SetGCInfo(varDsc->lvGcLayout, varDsc->lvStructGcCount, slots);
+ objNode->ChangeOper(GT_STORE_OBJ);
+ objNode->SetData(value);
+ comp->fgMorphUnsafeBlk(objNode);
+ storeBlk = objNode;
+ }
+ else
+ {
+ storeBlk = new (comp, GT_STORE_BLK) GenTreeBlk(GT_STORE_BLK, TYP_STRUCT, location, value, size);
+ }
+ storeBlk->gtFlags |= (GTF_REVERSE_OPS | GTF_ASG);
+ storeBlk->gtFlags |= ((location->gtFlags | value->gtFlags) & GTF_ALL_EFFECT);
+
+ GenTree* insertionPoint = location->gtNext;
+ BlockRange().InsertBefore(insertionPoint, storeBlk);
+ use.ReplaceWith(comp, storeBlk);
+ BlockRange().Remove(assignment);
+ JITDUMP("After transforming local struct assignment into a block op:\n");
+ DISPTREERANGE(BlockRange(), use.Def());
+ JITDUMP("\n");
+ return;
+ }
+ else
+ {
+ assert(location->OperIsBlk());
+ }
}
}
-#endif // FEATURE_SIMD
switch (locationOp)
{
@@ -539,7 +583,7 @@ void Rationalizer::RewriteAssignment(LIR::Use& use)
storeBlk->SetOperRaw(storeOper);
storeBlk->gtFlags &= ~GTF_DONT_CSE;
storeBlk->gtFlags |= (assignment->gtFlags & (GTF_ALL_EFFECT | GTF_REVERSE_OPS | GTF_BLK_VOLATILE |
- GTF_BLK_UNALIGNED | GTF_BLK_INIT | GTF_DONT_CSE));
+ GTF_BLK_UNALIGNED | GTF_DONT_CSE));
storeBlk->gtBlk.Data() = value;
// Replace the assignment node with the store