diff options
author | Pat Gavlin <pagavlin@microsoft.com> | 2017-06-07 15:09:29 -0700 |
---|---|---|
committer | Pat Gavlin <pagavlin@microsoft.com> | 2017-06-07 17:18:32 -0700 |
commit | 585d4d779053c7986d29d4f0d486702c6ecaaded (patch) | |
tree | c8fc9fd50fae4221cb83be96585f8840a8b6c957 /src | |
parent | cd5de7576d93f6006c4ef1659e3760488e159e82 (diff) | |
download | coreclr-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.cpp | 42 |
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; } |