summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPat Gavlin <pagavlin@microsoft.com>2017-06-07 15:09:29 -0700
committerPat Gavlin <pagavlin@microsoft.com>2017-06-07 17:18:32 -0700
commit585d4d779053c7986d29d4f0d486702c6ecaaded (patch)
treec8fc9fd50fae4221cb83be96585f8840a8b6c957 /src
parentcd5de7576d93f6006c4ef1659e3760488e159e82 (diff)
downloadcoreclr-585d4d779053c7986d29d4f0d486702c6ecaaded.tar.gz
coreclr-585d4d779053c7986d29d4f0d486702c6ecaaded.tar.bz2
coreclr-585d4d779053c7986d29d4f0d486702c6ecaaded.zip
Add lclVar semantic checks to CheckLIR.
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).
Diffstat (limited to 'src')
-rw-r--r--src/jit/lir.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/src/jit/lir.cpp b/src/jit/lir.cpp
index 383f9c3992..a616323181 100644
--- a/src/jit/lir.cpp
+++ b/src/jit/lir.cpp
@@ -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;
}