#include "jitpch.h"
#include "smallhash.h"
+#include "sideeffects.h"
#ifdef _MSC_VER
#pragma hdrstop
}
}
+ // 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;
}