Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit c00e407

Browse files
authored
Merge pull request #7410 from pgavlin/gh7380-1.1
Fix lowering's containment analysis.
2 parents fa699f8 + 252a234 commit c00e407

15 files changed

+1026
-74
lines changed

src/jit/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ set( JIT_SOURCES
6363
regset.cpp
6464
scopeinfo.cpp
6565
sharedfloat.cpp
66+
sideeffects.cpp
6667
sm.cpp
6768
smdata.cpp
6869
smweights.cpp

src/jit/codegenxarch.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5133,13 +5133,13 @@ regNumber CodeGen::genConsumeReg(GenTree* tree)
51335133
// Do liveness update for an address tree: one of GT_LEA, GT_LCL_VAR, or GT_CNS_INT (for call indirect).
51345134
void CodeGen::genConsumeAddress(GenTree* addr)
51355135
{
5136-
if (addr->OperGet() == GT_LEA)
5136+
if (!addr->isContained())
51375137
{
5138-
genConsumeAddrMode(addr->AsAddrMode());
5138+
genConsumeReg(addr);
51395139
}
5140-
else if (!addr->isContained())
5140+
else if (addr->OperGet() == GT_LEA)
51415141
{
5142-
genConsumeReg(addr);
5142+
genConsumeAddrMode(addr->AsAddrMode());
51435143
}
51445144
}
51455145

src/jit/gentree.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1607,6 +1607,30 @@ regMaskTP GenTreeCall::GetOtherRegMask() const
16071607
return resultMask;
16081608
}
16091609

1610+
//-------------------------------------------------------------------------
1611+
// IsPure:
1612+
// Returns true if this call is pure. For now, this uses the same
1613+
// definition of "pure" that is that used by HelperCallProperties: a
1614+
// pure call does not read or write any aliased (e.g. heap) memory or
1615+
// have other global side effects (e.g. class constructors, finalizers),
1616+
// but is allowed to throw an exception.
1617+
//
1618+
// NOTE: this call currently only returns true if the call target is a
1619+
// helper method that is known to be pure. No other analysis is
1620+
// performed.
1621+
//
1622+
// Arguments:
1623+
// Copiler - the compiler context.
1624+
//
1625+
// Returns:
1626+
// True if the call is pure; false otherwise.
1627+
//
1628+
bool GenTreeCall::IsPure(Compiler* compiler) const
1629+
{
1630+
return (gtCallType == CT_HELPER) &&
1631+
compiler->s_helperCallProperties.IsPure(compiler->eeGetHelperNum(gtCallMethHnd));
1632+
}
1633+
16101634
#ifndef LEGACY_BACKEND
16111635

16121636
//-------------------------------------------------------------------------

src/jit/gentree.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,6 +1365,7 @@ struct GenTree
13651365
{
13661366
case GT_LOCKADD:
13671367
case GT_XADD:
1368+
case GT_XCHG:
13681369
case GT_CMPXCHG:
13691370
case GT_BLK:
13701371
case GT_OBJ:
@@ -1404,7 +1405,7 @@ struct GenTree
14041405
return (gtOper == GT_XADD || gtOper == GT_XCHG || gtOper == GT_LOCKADD || gtOper == GT_CMPXCHG);
14051406
}
14061407

1407-
bool OperIsAtomicOp()
1408+
bool OperIsAtomicOp() const
14081409
{
14091410
return OperIsAtomicOp(gtOper);
14101411
}
@@ -3306,6 +3307,8 @@ struct GenTreeCall final : public GenTree
33063307
return (gtCallMoreFlags & GTF_CALL_M_DOES_NOT_RETURN) != 0;
33073308
}
33083309

3310+
bool IsPure(Compiler* compiler) const;
3311+
33093312
unsigned short gtCallMoreFlags; // in addition to gtFlags
33103313

33113314
unsigned char gtCallType : 3; // value from the gtCallTypes enumeration

src/jit/hashbv.cpp

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,19 @@ elemType hashBvNode::SubtractWithChange(hashBvNode* other)
289289
return result;
290290
}
291291

292+
bool hashBvNode::Intersects(hashBvNode* other)
293+
{
294+
for (int i = 0; i < this->numElements(); i++)
295+
{
296+
if ((this->elements[i] & other->elements[i]) != 0)
297+
{
298+
return true;
299+
}
300+
}
301+
302+
return false;
303+
}
304+
292305
void hashBvNode::AndWith(hashBvNode* other)
293306
{
294307
for (int i = 0; i < this->numElements(); i++)
@@ -1234,6 +1247,46 @@ class CompareAction
12341247
}
12351248
};
12361249

1250+
class IntersectsAction
1251+
{
1252+
public:
1253+
static inline void PreAction(hashBv* lhs, hashBv* rhs)
1254+
{
1255+
}
1256+
static inline void PostAction(hashBv* lhs, hashBv* rhs)
1257+
{
1258+
}
1259+
static inline bool DefaultResult()
1260+
{
1261+
return false;
1262+
}
1263+
1264+
static inline void LeftGap(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate)
1265+
{
1266+
// in rhs, not lhs
1267+
// so skip rhs
1268+
r = r->next;
1269+
}
1270+
static inline void RightGap(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate)
1271+
{
1272+
// in lhs, not rhs
1273+
// so skip lhs
1274+
l = &((*l)->next);
1275+
}
1276+
static inline void BothPresent(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate)
1277+
{
1278+
if ((*l)->Intersects(r))
1279+
{
1280+
terminate = true;
1281+
result = true;
1282+
}
1283+
}
1284+
static inline void LeftEmpty(hashBv* lhs, hashBvNode**& l, hashBvNode*& r, bool& result, bool& terminate)
1285+
{
1286+
r = r->next;
1287+
}
1288+
};
1289+
12371290
template <typename Action>
12381291
bool hashBv::MultiTraverseLHSBigger(hashBv* other)
12391292
{
@@ -1507,6 +1560,11 @@ bool hashBv::MultiTraverse(hashBv* other)
15071560
}
15081561
}
15091562

1563+
bool hashBv::Intersects(hashBv* other)
1564+
{
1565+
return MultiTraverse<IntersectsAction>(other);
1566+
}
1567+
15101568
bool hashBv::AndWithChange(hashBv* other)
15111569
{
15121570
return MultiTraverse<AndAction>(other);

src/jit/hashbv.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ class hashBvNode
157157
elemType XorWithChange(hashBvNode* other);
158158
elemType SubtractWithChange(hashBvNode* other);
159159

160+
bool Intersects(hashBvNode* other);
161+
160162
#ifdef DEBUG
161163
void dump();
162164
#endif // DEBUG
@@ -253,6 +255,8 @@ class hashBv
253255
bool XorWithChange(hashBv* other);
254256
bool SubtractWithChange(hashBv* other);
255257

258+
bool Intersects(hashBv* other);
259+
256260
template <class Action>
257261
bool MultiTraverseLHSBigger(hashBv* other);
258262
template <class Action>

src/jit/jit.settings.targets

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
<CppCompile Include="..\jitconfig.cpp" />
8787
<CppCompile Include="..\hostallocator.cpp" />
8888
<CppCompile Include="..\objectalloc.cpp" />
89+
<CppCompile Inlcude="..\sideeffects.cpp" />
8990
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='True'" Include="..\CodeGenLegacy.cpp" />
9091
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\Lower.cpp" />
9192
<CppCompile Condition="'$(ClDefines.Contains(`LEGACY_BACKEND`))'=='False'" Include="..\LSRA.cpp" />

src/jit/lower.cpp

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -78,34 +78,20 @@ bool Lowering::CheckImmedAndMakeContained(GenTree* parentNode, GenTree* childNod
7878
// and returns 'true' iff memory operand childNode can be contained in parentNode.
7979
//
8080
// Arguments:
81-
// parentNode - a non-leaf binary node
82-
// childNode - a memory op that is a child op of 'parentNode'
81+
// parentNode - any non-leaf node
82+
// childNode - some node that is an input to `parentNode`
8383
//
8484
// Return value:
8585
// true if it is safe to make childNode a contained memory operand.
8686
//
8787
bool Lowering::IsSafeToContainMem(GenTree* parentNode, GenTree* childNode)
8888
{
89-
assert(parentNode->OperIsBinary());
90-
assert(childNode->isMemoryOp());
89+
m_scratchSideEffects.Clear();
90+
m_scratchSideEffects.AddNode(comp, childNode);
9191

92-
unsigned int childFlags = (childNode->gtFlags & GTF_ALL_EFFECT);
93-
94-
GenTree* node;
95-
for (node = childNode; node != parentNode; node = node->gtNext)
92+
for (GenTree* node = childNode->gtNext; node != parentNode; node = node->gtNext)
9693
{
97-
assert(node != nullptr);
98-
99-
if ((childFlags != 0) && node->IsCall())
100-
{
101-
bool isPureHelper = (node->gtCall.gtCallType == CT_HELPER) &&
102-
comp->s_helperCallProperties.IsPure(comp->eeGetHelperNum(node->gtCall.gtCallMethHnd));
103-
if (!isPureHelper && ((node->gtFlags & childFlags & GTF_ALL_EFFECT) != 0))
104-
{
105-
return false;
106-
}
107-
}
108-
else if (node->OperIsStore() && comp->fgNodesMayInterfere(node, childNode))
94+
if (m_scratchSideEffects.InterferesWith(comp, node, false))
10995
{
11096
return false;
11197
}
@@ -2978,17 +2964,57 @@ void Lowering::AddrModeCleanupHelper(GenTreeAddrMode* addrMode, GenTree* node)
29782964
BlockRange().Remove(node);
29792965
}
29802966

2981-
// given two nodes which will be used in an addressing mode (base, index)
2982-
// walk backwards from the use to those nodes to determine if they are
2983-
// potentially modified in that range
2967+
//------------------------------------------------------------------------
2968+
// Lowering::AreSourcesPossibleModifiedLocals:
2969+
// Given two nodes which will be used in an addressing mode (base,
2970+
// index), check to see if they are lclVar reads, and if so, walk
2971+
// backwards from the use until both reads have been visited to
2972+
// determine if they are potentially modified in that range.
2973+
//
2974+
// Arguments:
2975+
// addr - the node that uses the base and index nodes
2976+
// base - the base node
2977+
// index - the index node
2978+
//
2979+
// Returns: true if either the base or index may be modified between the
2980+
// node and addr.
29842981
//
2985-
// returns: true if the sources given may be modified before they are used
2986-
bool Lowering::AreSourcesPossiblyModified(GenTree* addr, GenTree* base, GenTree* index)
2982+
bool Lowering::AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index)
29872983
{
29882984
assert(addr != nullptr);
29892985

2990-
for (GenTree* cursor = addr; cursor != nullptr; cursor = cursor->gtPrev)
2986+
unsigned markCount = 0;
2987+
2988+
SideEffectSet baseSideEffects;
2989+
if (base != nullptr)
29912990
{
2991+
if (base->OperIsLocalRead())
2992+
{
2993+
baseSideEffects.AddNode(comp, base);
2994+
}
2995+
else
2996+
{
2997+
base = nullptr;
2998+
}
2999+
}
3000+
3001+
SideEffectSet indexSideEffects;
3002+
if (index != nullptr)
3003+
{
3004+
if (index->OperIsLocalRead())
3005+
{
3006+
indexSideEffects.AddNode(comp, index);
3007+
}
3008+
else
3009+
{
3010+
index = nullptr;
3011+
}
3012+
}
3013+
3014+
for (GenTree* cursor = addr;; cursor = cursor->gtPrev)
3015+
{
3016+
assert(cursor != nullptr);
3017+
29923018
if (cursor == base)
29933019
{
29943020
base = nullptr;
@@ -2999,17 +3025,19 @@ bool Lowering::AreSourcesPossiblyModified(GenTree* addr, GenTree* base, GenTree*
29993025
index = nullptr;
30003026
}
30013027

3002-
if (base == nullptr && index == nullptr)
3028+
if ((base == nullptr) && (index == nullptr))
30033029
{
30043030
return false;
30053031
}
30063032

3007-
if (base != nullptr && comp->fgNodesMayInterfere(base, cursor))
3033+
m_scratchSideEffects.Clear();
3034+
m_scratchSideEffects.AddNode(comp, cursor);
3035+
if ((base != nullptr) && m_scratchSideEffects.InterferesWith(baseSideEffects, false))
30083036
{
30093037
return true;
30103038
}
30113039

3012-
if (index != nullptr && comp->fgNodesMayInterfere(index, cursor))
3040+
if ((index != nullptr) && m_scratchSideEffects.InterferesWith(indexSideEffects, false))
30133041
{
30143042
return true;
30153043
}
@@ -3092,7 +3120,7 @@ GenTree* Lowering::TryCreateAddrMode(LIR::Use&& use, bool isIndir)
30923120
}
30933121

30943122
// make sure there are not any side effects between def of leaves and use
3095-
if (!doAddrMode || AreSourcesPossiblyModified(addr, base, index))
3123+
if (!doAddrMode || AreSourcesPossiblyModifiedLocals(addr, base, index))
30963124
{
30973125
JITDUMP(" No addressing mode\n");
30983126
return addr;
@@ -3122,7 +3150,8 @@ GenTree* Lowering::TryCreateAddrMode(LIR::Use&& use, bool isIndir)
31223150
GenTreeAddrMode* addrMode = new (comp, GT_LEA) GenTreeAddrMode(addrModeType, base, index, scale, offset);
31233151

31243152
addrMode->gtRsvdRegs = addr->gtRsvdRegs;
3125-
addrMode->gtFlags |= (addr->gtFlags & (GTF_ALL_EFFECT | GTF_IND_FLAGS));
3153+
addrMode->gtFlags |= (addr->gtFlags & GTF_IND_FLAGS);
3154+
addrMode->gtFlags &= ~GTF_ALL_EFFECT; // LEAs are side-effect-free.
31263155

31273156
JITDUMP("New addressing mode node:\n");
31283157
DISPNODE(addrMode);

src/jit/lower.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1717
#include "compiler.h"
1818
#include "phase.h"
1919
#include "lsra.h"
20+
#include "sideeffects.h"
2021

2122
class Lowering : public Phase
2223
{
@@ -228,6 +229,7 @@ class Lowering : public Phase
228229
void LowerCmp(GenTreePtr tree);
229230

230231
#if !CPU_LOAD_STORE_ARCH
232+
bool IsRMWIndirCandidate(GenTree* operand, GenTree* storeInd);
231233
bool IsBinOpInRMWStoreInd(GenTreePtr tree);
232234
bool IsRMWMemOpRootedAtStoreInd(GenTreePtr storeIndTree, GenTreePtr* indirCandidate, GenTreePtr* indirOpSource);
233235
bool SetStoreIndOpCountsIfRMWMemOp(GenTreePtr storeInd);
@@ -247,7 +249,7 @@ class Lowering : public Phase
247249
private:
248250
static bool NodesAreEquivalentLeaves(GenTreePtr candidate, GenTreePtr storeInd);
249251

250-
bool AreSourcesPossiblyModified(GenTree* addr, GenTree* base, GenTree* index);
252+
bool AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index);
251253

252254
// return true if 'childNode' is an immediate that can be contained
253255
// by the 'parentNode' (i.e. folded into an instruction)
@@ -269,9 +271,10 @@ class Lowering : public Phase
269271
return LIR::AsRange(m_block);
270272
}
271273

272-
LinearScan* m_lsra;
273-
unsigned vtableCallTemp; // local variable we use as a temp for vtable calls
274-
BasicBlock* m_block;
274+
LinearScan* m_lsra;
275+
unsigned vtableCallTemp; // local variable we use as a temp for vtable calls
276+
SideEffectSet m_scratchSideEffects; // SideEffectSet used for IsSafeToContainMem and isRMWIndirCandidate
277+
BasicBlock* m_block;
275278
};
276279

277280
#endif // _LOWER_H_

src/jit/lowerarm.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
2828
#ifdef _TARGET_ARM_
2929

3030
#include "jit.h"
31+
#include "sideeffects.h"
3132
#include "lower.h"
3233
#include "lsra.h"
3334

0 commit comments

Comments
 (0)