Add lclVar semantic checks to CheckLIR.
authorPat Gavlin <pagavlin@microsoft.com>
Wed, 7 Jun 2017 22:09:29 +0000 (15:09 -0700)
committerPat Gavlin <pagavlin@microsoft.com>
Thu, 8 Jun 2017 00:18:32 +0000 (17:18 -0700)
Specifically, ensure that an unaliasable lclVar is not redefined between the
point at which a use appears in linear order and the point at which that
use is consumed by its user. This ensures that it is always safe to treat
a lclVar use as happening at the user (rather than at the lclVar node).

Commit migrated from https://github.com/dotnet/coreclr/commit/585d4d779053c7986d29d4f0d486702c6ecaaded

src/coreclr/src/jit/lir.cpp

index 383f9c3..a616323 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "jitpch.h"
 #include "smallhash.h"
+#include "sideeffects.h"
 
 #ifdef _MSC_VER
 #pragma hdrstop
@@ -1556,6 +1557,47 @@ bool LIR::Range::CheckLIR(Compiler* compiler, bool checkUnusedValues) const
         }
     }
 
+    // Check lclVar semantics: specifically, ensure that an unaliasable lclVar is not redefined between the
+    // point at which a use appears in linear order and the point at which that use is consumed by its user.
+    // This ensures that it is always safe to treat a lclVar use as happening at the user (rather than at
+    // the lclVar node).
+    //
+    // This happens as a second pass because unused lclVar reads may otherwise appear as outstanding reads
+    // and produce false indications that a write to a lclVar occurs while outstanding reads of that lclVar
+    // exist.
+    SmallHashTable<int, int, 32> unconsumedLclVarReads(compiler);
+    for (GenTree* node : *this)
+    {
+        for (GenTree* operand : node->Operands())
+        {
+            AliasSet::NodeInfo operandInfo(compiler, operand);
+            if (operandInfo.IsLclVarRead())
+            {
+                int count = 0;
+                if (unconsumedLclVarReads.TryRemove(operandInfo.LclNum(), &count) && count > 1)
+                {
+                    unconsumedLclVarReads.AddOrUpdate(operandInfo.LclNum(), count - 1);
+                }
+            }
+        }
+
+        AliasSet::NodeInfo nodeInfo(compiler, node);
+
+        bool unused;
+        if (nodeInfo.IsLclVarRead() && !unusedDefs.TryGetValue(node, &unused))
+        {
+            int count = 0;
+            unconsumedLclVarReads.TryGetValue(nodeInfo.LclNum(), &count);
+            unconsumedLclVarReads.AddOrUpdate(nodeInfo.LclNum(), count + 1);
+        }
+
+        if (nodeInfo.IsLclVarWrite())
+        {
+            int unused;
+            assert(!unconsumedLclVarReads.TryGetValue(nodeInfo.LclNum(), &unused));
+        }
+    }
+
     return true;
 }