@@ -78,14 +78,21 @@ struct State {
78
78
// / RegMaxValues stores registers that we know have a value in the
79
79
// / range [0, MaxValue-1].
80
80
SmallDenseMap<MCPhysReg, uint64_t , 1 > RegMaxValues;
81
- // / RegsFixedOffsetFromOrigSP contains the registers that contain the value
82
- // / of the original SP at the function start, or a fixed offset from it.
81
+ // / Reg2MaxOffset contains the registers that contain the value
82
+ // / of SP at some point during the running function, where it's
83
+ // / guaranteed that at the time the SP value was stored in the register,
84
+ // / a maximum offset for any probe into the stack is a constant.
85
+ // / That constant is stored in this map.
86
+ // /
83
87
// / This is especially useful to recognize frame pointers and the fact
84
88
// / that epilogues can restore stack pointers from frame pointer values.
85
89
// / This is only tracked in Basic Blocks that are known to be reachable
86
90
// / from an entry block. For blocks not (yet) known to be reachable from
87
91
// / an entry block, the optional does not contain a value.
88
- std::optional<SmallSet<MCPhysReg, 2 >> RegsFixedOffsetFromOrigSP;
92
+ std::optional<SmallDenseMap<MCPhysReg, int64_t , 2 >> Reg2MaxOffset;
93
+ // FIXME: It seems that conceptually it does not make sense to
94
+ // track wheterh the SP value is currently at a fixed offset from
95
+ // the value it was at function entry.
89
96
// / SPFixedOffsetFromOrig indicates whether the current SP value is
90
97
// / a constant fixed offset from the SP value at the function start.
91
98
std::optional<int64_t > SPFixedOffsetFromOrig;
@@ -131,16 +138,17 @@ struct State {
131
138
else if (*SPFixedOffsetFromOrig != *StateIn.SPFixedOffsetFromOrig )
132
139
SPFixedOffsetFromOrig.reset ();
133
140
134
- if (StateIn.RegsFixedOffsetFromOrigSP && RegsFixedOffsetFromOrigSP) {
135
- SmallVector<MCPhysReg, 2 > RegsToRemove;
136
- for (MCPhysReg R : *RegsFixedOffsetFromOrigSP)
137
- if (!StateIn.RegsFixedOffsetFromOrigSP ->contains (R))
138
- RegsToRemove.push_back (R);
139
- for (MCPhysReg R : RegsToRemove)
140
- RegsFixedOffsetFromOrigSP->erase (R);
141
- } else if (StateIn.RegsFixedOffsetFromOrigSP &&
142
- !RegsFixedOffsetFromOrigSP) {
143
- RegsFixedOffsetFromOrigSP = StateIn.RegsFixedOffsetFromOrigSP ;
141
+ if (StateIn.Reg2MaxOffset && Reg2MaxOffset) {
142
+ SmallDenseMap<MCPhysReg, int64_t , 2 > MergedMap;
143
+ for (auto R2MaxOff : *Reg2MaxOffset) {
144
+ const MCPhysReg R = R2MaxOff.first ;
145
+ if (auto SIn_R2MaxOff = StateIn.Reg2MaxOffset ->find (R);
146
+ SIn_R2MaxOff != StateIn.Reg2MaxOffset ->end ())
147
+ MergedMap[R] = std::max (R2MaxOff.second , SIn_R2MaxOff->second );
148
+ }
149
+ Reg2MaxOffset = MergedMap;
150
+ } else if (StateIn.Reg2MaxOffset && !Reg2MaxOffset) {
151
+ Reg2MaxOffset = StateIn.Reg2MaxOffset ;
144
152
}
145
153
146
154
for (auto I : StateIn.LastStackGrowingInsts )
@@ -152,7 +160,7 @@ struct State {
152
160
RegConstValues == RHS.RegConstValues &&
153
161
RegMaxValues == RHS.RegMaxValues &&
154
162
SPFixedOffsetFromOrig == RHS.SPFixedOffsetFromOrig &&
155
- RegsFixedOffsetFromOrigSP == RHS.RegsFixedOffsetFromOrigSP ;
163
+ Reg2MaxOffset == RHS.Reg2MaxOffset ;
156
164
}
157
165
bool operator !=(const State &RHS) const { return !((*this ) == RHS); }
158
166
};
@@ -168,8 +176,8 @@ void print_reg(raw_ostream &OS, MCPhysReg Reg, const BinaryContext *BC) {
168
176
}
169
177
}
170
178
171
- void PrintRegMap (raw_ostream &OS,
172
- const SmallDenseMap<MCPhysReg, uint64_t , 1 > &M,
179
+ template < class T , unsigned N>
180
+ void PrintRegMap (raw_ostream &OS, const SmallDenseMap<MCPhysReg, T, N > &M,
173
181
const BinaryContext *BC = nullptr ) {
174
182
for (auto Reg2Value : M) {
175
183
print_reg (OS, Reg2Value.first , BC);
@@ -185,18 +193,15 @@ raw_ostream &print_state(raw_ostream &OS, const State &S,
185
193
else
186
194
OS << *(S.MaxOffsetSinceLastProbe );
187
195
OS << " ), RegConstValues(" ;
188
- PrintRegMap (OS, S.RegConstValues );
196
+ PrintRegMap (OS, S.RegConstValues , BC );
189
197
OS << " ), RegMaxValues(" ;
190
- PrintRegMap (OS, S.RegMaxValues );
198
+ PrintRegMap (OS, S.RegMaxValues , BC );
191
199
OS << " )," ;
192
200
OS << " SPFixedOffsetFromOrig:" << S.SPFixedOffsetFromOrig << " ," ;
193
- OS << " RegsFixedOffsetFromOrigSP :" ;
194
- if (S.RegsFixedOffsetFromOrigSP ) {
201
+ OS << " Reg2MaxOffset :" ;
202
+ if (S.Reg2MaxOffset ) {
195
203
OS << " (" ;
196
- for (auto Reg : *S.RegsFixedOffsetFromOrigSP ) {
197
- print_reg (OS, Reg, BC);
198
- OS << " ," ;
199
- }
204
+ PrintRegMap (OS, *S.Reg2MaxOffset , BC);
200
205
OS << " )" ;
201
206
} else
202
207
OS << " None" ;
@@ -243,7 +248,7 @@ class StackClashDFAnalysis
243
248
State getStartingStateAtBB (const BinaryBasicBlock &BB) {
244
249
State Next;
245
250
if (BB.isEntryPoint ())
246
- Next.RegsFixedOffsetFromOrigSP = SmallSet <MCPhysReg, 2 >();
251
+ Next.Reg2MaxOffset = SmallDenseMap <MCPhysReg, int64_t , 2 >();
247
252
return Next;
248
253
}
249
254
@@ -351,16 +356,29 @@ class StackClashDFAnalysis
351
356
MCPhysReg FixedOffsetRegJustSet = BC.MIB ->getNoRegister ();
352
357
if (auto OC = BC.MIB ->getOffsetChange (Point, Cur.RegConstValues ,
353
358
Cur.RegMaxValues ))
354
- if (Next.RegsFixedOffsetFromOrigSP )
355
- if (OC.FromReg == SP ||
356
- Cur.RegsFixedOffsetFromOrigSP ->contains (OC.FromReg )) {
357
- Next.RegsFixedOffsetFromOrigSP ->insert (OC.ToReg );
359
+ if (Next.Reg2MaxOffset ) {
360
+ if (OC.FromReg == SP) {
361
+ (*Next.Reg2MaxOffset )[OC.ToReg ] = *Cur.MaxOffsetSinceLastProbe ;
358
362
FixedOffsetRegJustSet = OC.ToReg ;
363
+ } else if (auto I = Cur.Reg2MaxOffset ->find (OC.FromReg );
364
+ I != Cur.Reg2MaxOffset ->end ()) {
365
+ (*Next.Reg2MaxOffset )[OC.ToReg ] = (*I).second ;
366
+ FixedOffsetRegJustSet = OC.ToReg ;
367
+ }
368
+ }
369
+ if (Next.Reg2MaxOffset )
370
+ for (const MCOperand &Operand : BC.MIB ->defOperands (Point)) {
371
+ if (Operand.getReg () != FixedOffsetRegJustSet) {
372
+ Next.Reg2MaxOffset ->erase (Operand.getReg ());
373
+ LLVM_DEBUG ({
374
+ dbgs () << " - Removed Reg " << Operand.getReg ()
375
+ << " from Next.Reg2MaxOffset"
376
+ << " . On instruction:" ;
377
+ BC.printInstruction (dbgs (), Point);
378
+ dbgs () << " \n " ;
379
+ });
359
380
}
360
- if (Next.RegsFixedOffsetFromOrigSP )
361
- for (const MCOperand &Operand : BC.MIB ->defOperands (Point))
362
- if (Operand.getReg () != FixedOffsetRegJustSet)
363
- Next.RegsFixedOffsetFromOrigSP ->erase (Operand.getReg ());
381
+ }
364
382
365
383
if (BC.MIB ->hasDefOfPhysReg (Point, SP)) {
366
384
// Next, validate that we can track by how much the SP
@@ -371,37 +389,46 @@ class StackClashDFAnalysis
371
389
Next.LastStackGrowingInsts .insert (MCInstInBBReference::get (&Point, BF));
372
390
if (auto OC = BC.MIB ->getOffsetChange (Point, Cur.RegConstValues ,
373
391
Cur.RegMaxValues );
374
- OC && OC.ToReg == SP && OC.FromReg == SP) {
375
- assert (OC.MaxOffsetChange );
376
- if (*OC.MaxOffsetChange < 0 )
377
- Next.MaxOffsetSinceLastProbe =
378
- *Next.MaxOffsetSinceLastProbe - *OC.MaxOffsetChange ;
379
- if (OC.OffsetChange && Next.SPFixedOffsetFromOrig )
380
- Next.SPFixedOffsetFromOrig =
381
- *Next.SPFixedOffsetFromOrig + *OC.OffsetChange ;
382
- // FIXME: add test case for this if test.
392
+ OC && OC.ToReg == SP) {
393
+ if (OC.FromReg == SP) {
394
+ assert (OC.MaxOffsetChange );
395
+ if (*OC.MaxOffsetChange < 0 )
396
+ Next.MaxOffsetSinceLastProbe =
397
+ *Next.MaxOffsetSinceLastProbe - *OC.MaxOffsetChange ;
398
+ if (OC.OffsetChange && Next.SPFixedOffsetFromOrig )
399
+ Next.SPFixedOffsetFromOrig =
400
+ *Next.SPFixedOffsetFromOrig + *OC.OffsetChange ;
401
+ // FIXME: add test case for this if test.
383
402
#if 0
384
403
if (IsPreIndexOffsetChange)
385
404
Next.MaxOffsetSinceLastProbe =
386
405
*Next.MaxOffsetSinceLastProbe - StackAccessOffset;
387
406
#endif
388
- LLVM_DEBUG ({
389
- dbgs () << " Found SP Offset change: " ;
390
- BC.printInstruction (dbgs (), Point);
391
- dbgs () << " OffsetChange: " << OC.OffsetChange
392
- << " ; MaxOffsetChange: " << OC.MaxOffsetChange
393
- << " ; new MaxOffsetSinceLastProbe: "
394
- << Next.MaxOffsetSinceLastProbe
395
- << " ; new SPFixedOffsetFromOrig: "
396
- << Next.SPFixedOffsetFromOrig
397
- << " ; IsStackAccess:" << IsStackAccess
398
- << " ; StackAccessOffset: " << StackAccessOffset << " \n " ;
399
- });
400
- assert (!OC.IsPreIndexOffsetChange || IsStackAccess);
401
- assert (*Next.MaxOffsetSinceLastProbe >= 0 );
407
+ LLVM_DEBUG ({
408
+ dbgs () << " Found SP Offset change: " ;
409
+ BC.printInstruction (dbgs (), Point);
410
+ dbgs () << " OffsetChange: " << OC.OffsetChange
411
+ << " ; MaxOffsetChange: " << OC.MaxOffsetChange
412
+ << " ; new MaxOffsetSinceLastProbe: "
413
+ << Next.MaxOffsetSinceLastProbe
414
+ << " ; new SPFixedOffsetFromOrig: "
415
+ << Next.SPFixedOffsetFromOrig
416
+ << " ; IsStackAccess:" << IsStackAccess
417
+ << " ; StackAccessOffset: " << StackAccessOffset << " \n " ;
418
+ });
419
+ assert (!OC.IsPreIndexOffsetChange || IsStackAccess);
420
+ assert (*Next.MaxOffsetSinceLastProbe >= 0 );
421
+ } else if (
422
+ Cur.Reg2MaxOffset && Cur.Reg2MaxOffset ->contains (OC.FromReg ) &&
423
+ OC.OffsetChange ==
424
+ 0 /* FIXME: also handle other offset changes if needed. */ ) {
425
+ const int64_t MaxOffset = Cur.Reg2MaxOffset ->find (OC.FromReg )->second ;
426
+ Next.MaxOffsetSinceLastProbe = MaxOffset;
427
+ }
402
428
} else {
403
429
Next.MaxOffsetSinceLastProbe .reset ();
404
- Next.SPFixedOffsetFromOrig .reset ();
430
+ Next.SPFixedOffsetFromOrig
431
+ .reset (); // FIXME - should I make this the empty set?
405
432
LLVM_DEBUG ({
406
433
dbgs () << " Found non-const SP Offset change: " ;
407
434
BC.printInstruction (dbgs (), Point);
@@ -480,10 +507,12 @@ void StackClashAnalysis::runOnFunction(
480
507
// function into the SP, then we know this is probably fine.
481
508
// Typical case is moving the frame pointer to the stack pointer
482
509
// in the function epilogue.
483
- bool IsFixedRegToSPMove =
484
- OC && OC.ToReg == SP && S.RegsFixedOffsetFromOrigSP &&
485
- S.RegsFixedOffsetFromOrigSP ->contains (OC.FromReg );
486
- if (!IsFixedRegToSPMove) {
510
+ bool IsFixedRegToSPMove = OC && OC.ToReg == SP && S.Reg2MaxOffset &&
511
+ S.Reg2MaxOffset ->contains (OC.FromReg );
512
+ if (IsFixedRegToSPMove) {
513
+ S.MaxOffsetSinceLastProbe =
514
+ S.Reg2MaxOffset ->find (OC.FromReg )->second ;
515
+ } else {
487
516
// mark to report that this may be an SP change that is not a
488
517
// constant amount.
489
518
LLVM_DEBUG ({
0 commit comments