Skip to content

Commit 95119f4

Browse files
committed
[GS/StackClash] Introduce more general LatticeT class
to model dataflow operations on a "lattice" type with 1 "bottom" value, 1 "top" value, and a set of "regular" values.
1 parent 69b1abd commit 95119f4

File tree

1 file changed

+87
-46
lines changed

1 file changed

+87
-46
lines changed

bolt/lib/Passes/StackClashAnalysis.cpp

Lines changed: 87 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include "llvm/MC/MCInst.h"
2020
#include "llvm/Support/Format.h"
2121

22-
#include <limits>
22+
#include <functional>
2323

2424
#define DEBUG_TYPE "bolt-stackclash"
2525

@@ -70,51 +70,85 @@ bool addToMaxMap(SmallDenseMap<MCPhysReg, uint64_t, 1> &M, MCPhysReg R,
7070
}
7171
}
7272

73-
class MaxOffsetT {
73+
template <typename T, auto MergeValLambda> class LatticeT {
7474
private:
75-
int64_t V;
76-
// FIXME: should I add an "iteration count", and allow
77-
// "max" to be computed a few times. But if it's being
78-
// computed too many times, give up?
79-
75+
enum LValType { _Bottom, _Top, Value } LValType;
76+
T V;
77+
LatticeT(enum LValType ValType, T Val) : LValType(ValType), V(Val) {}
78+
static LatticeT _TopV; //(_Top, T());
79+
static LatticeT _BottomV; //(_Bottom, T());
8080
public:
81-
MaxOffsetT() : V(Bottom().V) {}
82-
MaxOffsetT(int64_t O) : V(O) {}
83-
static MaxOffsetT Top() { return std::numeric_limits<int64_t>::max(); }
84-
static MaxOffsetT Bottom() { return std::numeric_limits<int64_t>::min(); }
85-
static MaxOffsetT doConfluence(const MaxOffsetT O1, const MaxOffsetT O2) {
86-
if (O1 == O2)
87-
return O1;
88-
if (O1 == Bottom())
89-
return O2;
90-
if (O2 == Bottom())
91-
return O1;
92-
return Top();
81+
LatticeT() : LatticeT(_Bottom, T()) {}
82+
LatticeT(T V) : LatticeT(Value, V) {}
83+
static const LatticeT &Top() { return _TopV; }
84+
static const LatticeT &Bottom() { return _BottomV; }
85+
LatticeT &operator&=(const LatticeT &E2) {
86+
switch (E2.LValType) {
87+
case _Bottom:
88+
// nothing to do.
89+
break;
90+
case _Top:
91+
*this = Top();
92+
break;
93+
case Value:
94+
switch (LValType) {
95+
case _Bottom:
96+
*this = E2;
97+
break;
98+
case _Top:
99+
// nothing to do.
100+
break;
101+
case Value:
102+
if (!MergeValLambda(V, E2.V))
103+
*this = Top();
104+
break;
105+
}
106+
break;
107+
}
108+
return *this;
93109
}
94-
MaxOffsetT operator+(const int64_t Offset) const {
95-
assert(*this != Bottom());
96-
if (*this == Top())
97-
return Top();
98-
return MaxOffsetT(V + Offset);
110+
bool operator==(const LatticeT &RHS) const {
111+
return LValType == RHS.LValType && V == RHS.V;
99112
}
100-
bool operator==(const MaxOffsetT RHS) const { return V == RHS.V; }
101-
bool operator!=(const MaxOffsetT RHS) const { return !(*this == RHS); }
102-
int64_t getIntValue() const {
113+
bool operator!=(const LatticeT &RHS) const { return !(*this == RHS); }
114+
const T &getVal() const {
103115
assert(*this != Bottom() && *this != Top());
104116
return V;
105117
}
118+
LatticeT &doOnVal(std::function<const T &(T &, const T &)> f, const T &V2) {
119+
assert(*this != Bottom());
120+
if (*this == Top())
121+
return *this;
122+
V = f(V, V2);
123+
return *this;
124+
}
106125
};
107126

108-
raw_ostream &operator<<(raw_ostream &OS, MaxOffsetT O) {
109-
if (O == MaxOffsetT::Top())
127+
template <typename T, auto M> LatticeT<T, M> LatticeT<T, M>::_TopV(_Top, T());
128+
template <typename T, auto M>
129+
LatticeT<T, M> LatticeT<T, M>::_BottomV(_Bottom, T());
130+
131+
template <typename T, auto M>
132+
raw_ostream &operator<<(raw_ostream &OS, const LatticeT<T, M> &V) {
133+
if (V == V.Top())
110134
OS << "(T)";
111-
else if (O == MaxOffsetT::Bottom())
135+
else if (V == V.Bottom())
112136
OS << "(B)";
113137
else
114-
OS << O.getIntValue();
138+
OS << V.getVal();
115139
return OS;
116140
}
117141

142+
bool MaxOffsetMergeVal(int64_t &v1, const int64_t &v2) { return v1 == v2; }
143+
using MaxOffsetT = LatticeT<int64_t, MaxOffsetMergeVal>;
144+
const auto AddOffset = [](int64_t &v1, const int64_t &v2) -> const int64_t & {
145+
v1 += v2;
146+
return v1;
147+
};
148+
MaxOffsetT &operator+=(MaxOffsetT &O1, const int64_t O2) {
149+
return O1.doOnVal(AddOffset, O2);
150+
}
151+
118152
struct State {
119153
// Store the maximum possible offset to which the stack extends
120154
// beyond the furthest probe seen.
@@ -124,6 +158,8 @@ struct State {
124158
SmallDenseMap<MCPhysReg, uint64_t, 1> RegConstValues;
125159
/// RegMaxValues stores registers that we know have a value in the
126160
/// range [0, MaxValue-1].
161+
// FIXME: also make this std::optional!!!
162+
// FIXME: same for RegConstValues.
127163
SmallDenseMap<MCPhysReg, uint64_t, 1> RegMaxValues;
128164
/// Reg2MaxOffset contains the registers that contain the value
129165
/// of SP at some point during the running function, where it's
@@ -176,6 +212,8 @@ struct State {
176212
else
177213
Reg2MaxValue.second =
178214
std::max(Reg2MaxValue.second, SInReg2MaxValue->second);
215+
// FIXME: this should be a "confluence" - similar
216+
// to MaxOffsetT? To avoid near infinite loops?
179217
}
180218
for (MCPhysReg R : RegMaxValuesToRemove)
181219
RegMaxValues.erase(R);
@@ -186,20 +224,20 @@ struct State {
186224
SPFixedOffsetFromOrig.reset();
187225

188226
if (StateIn.Reg2MaxOffset && Reg2MaxOffset) {
189-
SmallDenseMap<MCPhysReg, MaxOffsetT, 2> MergedMap;
227+
SmallVector<MCPhysReg, 2> RToRemove;
190228
for (auto R2MaxOff : *Reg2MaxOffset) {
191229
const MCPhysReg R = R2MaxOff.first;
192230
if (auto SIn_R2MaxOff = StateIn.Reg2MaxOffset->find(R);
193-
SIn_R2MaxOff != StateIn.Reg2MaxOffset->end()) {
231+
SIn_R2MaxOff == StateIn.Reg2MaxOffset->end())
232+
RToRemove.push_back(R);
233+
else {
194234
MaxOffsetT MaxOff1 = R2MaxOff.second;
195235
MaxOffsetT MaxOff2 = SIn_R2MaxOff->second;
196-
MergedMap[R] = MaxOffsetT::doConfluence(MaxOff1, MaxOff2);
197-
#if 0
198-
std::max(R2MaxOff.second, SIn_R2MaxOff->second);
199-
#endif
236+
MaxOff1 &= MaxOff2;
200237
}
238+
for (auto R : RToRemove)
239+
Reg2MaxOffset->erase(R);
201240
}
202-
Reg2MaxOffset = MergedMap;
203241
} else if (StateIn.Reg2MaxOffset && !Reg2MaxOffset) {
204242
Reg2MaxOffset = StateIn.Reg2MaxOffset;
205243
}
@@ -333,13 +371,14 @@ bool checkNonConstSPOffsetChange(const BinaryContext &BC, BinaryFunction &BF,
333371
if (MaxOffset != MaxOffsetT::Top()) {
334372
if (Next) {
335373
Next->MaxOffsetSinceLastProbe =
336-
MaxOffset.getIntValue() - *OC.OffsetChange;
374+
MaxOffset.getVal() - *OC.OffsetChange;
337375
Next->SPFixedOffsetFromOrig = std::nullopt;
338376
}
339377
} else {
340378
// unlimited Max Offset
341379
if (Next) {
342-
Next->MaxOffsetSinceLastProbe = std::numeric_limits<int64_t>::max();//MaxOffsetT::Top();
380+
Next->MaxOffsetSinceLastProbe =
381+
std::numeric_limits<int64_t>::max(); // MaxOffsetT::Top();
343382
Next->SPFixedOffsetFromOrig = std::nullopt;
344383
}
345384
IsNonConstantSPOffsetChange = true;
@@ -358,11 +397,11 @@ bool checkNonConstSPOffsetChange(const BinaryContext &BC, BinaryFunction &BF,
358397
int64_t MaxOffsetChange = BitsToZeroMask + 1;
359398
IsNonConstantSPOffsetChange = false;
360399
MaxOffsetT MaxOffset = Cur.Reg2MaxOffset->find(FromReg)->second;
361-
MaxOffsetT NextOffset = MaxOffset + MaxOffsetChange;
362-
if (NextOffset == MaxOffsetT::Top())
400+
MaxOffset += MaxOffsetChange;
401+
if (MaxOffset == MaxOffsetT::Top())
363402
IsNonConstantSPOffsetChange = true;
364403
else if (Next) {
365-
Next->MaxOffsetSinceLastProbe = NextOffset.getIntValue();
404+
Next->MaxOffsetSinceLastProbe = MaxOffset.getVal();
366405
Next->SPFixedOffsetFromOrig = std::nullopt;
367406
}
368407
}
@@ -505,12 +544,14 @@ class StackClashDFAnalysis
505544
if (Next.Reg2MaxOffset && OC.OffsetChange) {
506545
int64_t Offset = *OC.OffsetChange;
507546
if (OC.FromReg == SP) {
508-
(*Next.Reg2MaxOffset)[OC.ToReg] =
509-
*Cur.MaxOffsetSinceLastProbe + (-Offset);
547+
MaxOffsetT &MaxOffset = (*Next.Reg2MaxOffset)[OC.ToReg] =
548+
*Cur.MaxOffsetSinceLastProbe;
549+
MaxOffset += (-Offset);
510550
FixedOffsetRegJustSet = OC.ToReg;
511551
} else if (auto I = Cur.Reg2MaxOffset->find(OC.FromReg);
512552
I != Cur.Reg2MaxOffset->end()) {
513-
(*Next.Reg2MaxOffset)[OC.ToReg] = (*I).second + (-Offset);
553+
MaxOffsetT &MaxOffset = (*Next.Reg2MaxOffset)[OC.ToReg] = (*I).second;
554+
MaxOffset += (-Offset);
514555
FixedOffsetRegJustSet = OC.ToReg;
515556
}
516557
}

0 commit comments

Comments
 (0)