Fix use edge iterator for DYN_BLK nodes.
authorPat Gavlin <pagavlin@microsoft.com>
Tue, 6 Dec 2016 23:37:08 +0000 (15:37 -0800)
committerPat Gavlin <pagavlin@microsoft.com>
Tue, 6 Dec 2016 23:37:08 +0000 (15:37 -0800)
Dynamic block nodes (i.e. DYN_BLK and STORE_DYN_BLK) are not standard
nodes. As such, the use order of their operands may be reordered in ways
that are not visible via the usual mechanisms. The use edge iterator was
not taking these mechanisms into account, which caused mismatches
between the use order observed by LSRA and the order observed by code
generation. This in turn caused SBCG under circumstances in which one
operand needed to be copied from e.g. esi to edi before another operand
was unspilled into esi.

Fixes VSO 297113.

src/jit/gentree.cpp

index a749cb5..4a6cc74 100644 (file)
@@ -9244,30 +9244,53 @@ GenTree** GenTreeUseEdgeIterator::GetNextUseEdge() const
         }
 
         case GT_DYN_BLK:
+        {
+            GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
             switch (m_state)
             {
                 case 0:
-                    return &(m_node->AsDynBlk()->gtOp1);
+                    return dynBlock->gtEvalSizeFirst ? &dynBlock->gtDynamicSize : &dynBlock->gtOp1;
                 case 1:
-                    return &(m_node->AsDynBlk()->gtDynamicSize);
+                    return dynBlock->gtEvalSizeFirst ? &dynBlock->gtOp1 : &dynBlock->gtDynamicSize;
                 default:
                     return nullptr;
             }
-            break;
+        }
+        break;
 
         case GT_STORE_DYN_BLK:
-            switch (m_state)
+        {
+            GenTreeDynBlk* const dynBlock = m_node->AsDynBlk();
+            if (dynBlock->gtEvalSizeFirst)
             {
-                case 0:
-                    return &(m_node->AsDynBlk()->gtOp1);
-                case 1:
-                    return &(m_node->AsDynBlk()->gtOp2);
-                case 2:
-                    return &(m_node->AsDynBlk()->gtDynamicSize);
-                default:
-                    return nullptr;
+                switch (m_state)
+                {
+                    case 0:
+                        return &dynBlock->gtDynamicSize;
+                    case 1:
+                        return dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
+                    case 2:
+                        return dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
+                    default:
+                        return nullptr;
+                }
             }
-            break;
+            else
+            {
+                switch (m_state)
+                {
+                    case 0:
+                        return dynBlock->IsReverseOp() ? &dynBlock->gtOp2 : &dynBlock->gtOp1;
+                    case 1:
+                        return dynBlock->IsReverseOp() ? &dynBlock->gtOp1 : &dynBlock->gtOp2;
+                    case 2:
+                        return &dynBlock->gtDynamicSize;
+                    default:
+                        return nullptr;
+                }
+            }
+        }
+        break;
 
         case GT_LEA:
         {