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 {
7474private:
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());
8080public:
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+
118152struct 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