From 2d109afe244ba75453a1692536fdf993508ee768 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 31 Aug 2018 08:20:53 -0700 Subject: [PATCH] JIT: don't allocate promoted struct death vars map for clear or lookup (dotnet/coreclr#19753) Only allocate this map if we're adding something. Refactor clearing and lookup to do minimal work if the map hasn't been allocated (and it won't have been in debug / minopts). Saves a tiny bit of throughput and memory. Commit migrated from https://github.com/dotnet/coreclr/commit/de74b8ca4116235601feaf868f3ab0a06615ec3d --- src/coreclr/src/jit/compiler.h | 29 +++++++++++++++++++++++++++-- src/coreclr/src/jit/liveness.cpp | 4 ++-- src/coreclr/src/jit/treelifeupdater.cpp | 10 ++++++---- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 24ade25..d46e571 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -7105,12 +7105,16 @@ public: // node, else NULL. static GenTree* fgIsIndirOfAddrOfLocal(GenTree* tree); - // This is indexed by GT_OBJ nodes that are address of promoted struct variables, which + // This map is indexed by GT_OBJ nodes that are address of promoted struct variables, which // have been annotated with the GTF_VAR_DEATH flag. If such a node is *not* mapped in this - // table, one may assume that all the (tracked) field vars die at this point. Otherwise, + // table, one may assume that all the (tracked) field vars die at this GT_OBJ. Otherwise, // the node maps to a pointer to a VARSET_TP, containing set bits for each of the tracked field // vars of the promoted struct local that go dead at the given node (the set bits are the bits // for the tracked var indices of the field vars, as in a live var set). + // + // The map is allocated on demand so all map operations should use one of the following three + // wrapper methods. + NodeToVarsetPtrMap* m_promotedStructDeathVars; NodeToVarsetPtrMap* GetPromotedStructDeathVars() @@ -7122,6 +7126,27 @@ public: return m_promotedStructDeathVars; } + void ClearPromotedStructDeathVars() + { + if (m_promotedStructDeathVars != nullptr) + { + m_promotedStructDeathVars->RemoveAll(); + } + } + + bool LookupPromotedStructDeathVars(GenTree* tree, VARSET_TP** bits) + { + bits = nullptr; + bool result = false; + + if (m_promotedStructDeathVars != nullptr) + { + result = m_promotedStructDeathVars->Lookup(tree, bits); + } + + return result; + } + /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX diff --git a/src/coreclr/src/jit/liveness.cpp b/src/coreclr/src/jit/liveness.cpp index 35edbfc..a92cc34 100644 --- a/src/coreclr/src/jit/liveness.cpp +++ b/src/coreclr/src/jit/liveness.cpp @@ -138,7 +138,7 @@ void Compiler::fgLocalVarLiveness() EndPhase(PHASE_LCLVARLIVENESS_INIT); // Make sure we haven't noted any partial last uses of promoted structs. - GetPromotedStructDeathVars()->RemoveAll(); + ClearPromotedStructDeathVars(); // Initialize the per-block var sets. fgInitBlockVarSets(); @@ -1340,7 +1340,7 @@ VARSET_VALRET_TP Compiler::fgUpdateLiveSet(VARSET_VALARG_TP liveSet, GenTree* tr // We maintain the invariant that if the lclVarTree is a promoted struct, but the // the lookup fails, then all the field vars (i.e., "varBits") are dying. VARSET_TP* deadVarBits = nullptr; - if (varTypeIsStruct(lclVarTree) && GetPromotedStructDeathVars()->Lookup(lclVarTree, &deadVarBits)) + if (varTypeIsStruct(lclVarTree) && LookupPromotedStructDeathVars(lclVarTree, &deadVarBits)) { VarSetOps::DiffD(this, newLiveSet, *deadVarBits); } diff --git a/src/coreclr/src/jit/treelifeupdater.cpp b/src/coreclr/src/jit/treelifeupdater.cpp index 5b5165e..ecfdaee 100644 --- a/src/coreclr/src/jit/treelifeupdater.cpp +++ b/src/coreclr/src/jit/treelifeupdater.cpp @@ -85,9 +85,6 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) if (isBorn || isDying) { - bool hasDeadTrackedFieldVars = false; // If this is true, then, for a LDOBJ(ADDR()), - VARSET_TP* deadTrackedFieldVars = - nullptr; // *deadTrackedFieldVars indicates which tracked field vars are dying. VarSetOps::ClearD(compiler, varDeltaSet); if (varDsc->lvTracked) @@ -111,11 +108,16 @@ void TreeLifeUpdater::UpdateLifeVar(GenTree* tree) } else if (varDsc->lvPromoted) { + // If hasDeadTrackedFieldVars is true, then, for a LDOBJ(ADDR()), + // *deadTrackedFieldVars indicates which tracked field vars are dying. + bool hasDeadTrackedFieldVars = false; + if (indirAddrLocal != nullptr && isDying) { assert(!isBorn); // GTF_VAR_DEATH only set for LDOBJ last use. + VARSET_TP* deadTrackedFieldVars = nullptr; hasDeadTrackedFieldVars = - compiler->GetPromotedStructDeathVars()->Lookup(indirAddrLocal, &deadTrackedFieldVars); + compiler->LookupPromotedStructDeathVars(indirAddrLocal, &deadTrackedFieldVars); if (hasDeadTrackedFieldVars) { VarSetOps::Assign(compiler, varDeltaSet, *deadTrackedFieldVars); -- 2.7.4