@@ -229,6 +229,9 @@ struct AADepGraph {
229
229
// / are floating values that do not have a corresponding attribute list
230
230
// / position.
231
231
struct IRPosition {
232
+ // NOTE: In the future this definition can be changed to support recursive
233
+ // functions.
234
+ using CallBaseContext = CallBase;
232
235
233
236
// / The positions we distinguish in the IR.
234
237
enum Kind : char {
@@ -249,27 +252,34 @@ struct IRPosition {
249
252
IRPosition () : Enc(nullptr , ENC_VALUE) { verify (); }
250
253
251
254
// / Create a position describing the value of \p V.
252
- static const IRPosition value (const Value &V) {
255
+ static const IRPosition value (const Value &V,
256
+ const CallBaseContext *CBContext = nullptr ) {
253
257
if (auto *Arg = dyn_cast<Argument>(&V))
254
- return IRPosition::argument (*Arg);
258
+ return IRPosition::argument (*Arg, CBContext );
255
259
if (auto *CB = dyn_cast<CallBase>(&V))
256
260
return IRPosition::callsite_returned (*CB);
257
- return IRPosition (const_cast <Value &>(V), IRP_FLOAT);
261
+ return IRPosition (const_cast <Value &>(V), IRP_FLOAT, CBContext );
258
262
}
259
263
260
264
// / Create a position describing the function scope of \p F.
261
- static const IRPosition function (const Function &F) {
262
- return IRPosition (const_cast <Function &>(F), IRP_FUNCTION);
265
+ // / \p CBContext is used for call base specific analysis.
266
+ static const IRPosition function (const Function &F,
267
+ const CallBaseContext *CBContext = nullptr ) {
268
+ return IRPosition (const_cast <Function &>(F), IRP_FUNCTION, CBContext);
263
269
}
264
270
265
271
// / Create a position describing the returned value of \p F.
266
- static const IRPosition returned (const Function &F) {
267
- return IRPosition (const_cast <Function &>(F), IRP_RETURNED);
272
+ // / \p CBContext is used for call base specific analysis.
273
+ static const IRPosition returned (const Function &F,
274
+ const CallBaseContext *CBContext = nullptr ) {
275
+ return IRPosition (const_cast <Function &>(F), IRP_RETURNED, CBContext);
268
276
}
269
277
270
278
// / Create a position describing the argument \p Arg.
271
- static const IRPosition argument (const Argument &Arg) {
272
- return IRPosition (const_cast <Argument &>(Arg), IRP_ARGUMENT);
279
+ // / \p CBContext is used for call base specific analysis.
280
+ static const IRPosition argument (const Argument &Arg,
281
+ const CallBaseContext *CBContext = nullptr ) {
282
+ return IRPosition (const_cast <Argument &>(Arg), IRP_ARGUMENT, CBContext);
273
283
}
274
284
275
285
// / Create a position describing the function scope of \p CB.
@@ -305,16 +315,20 @@ struct IRPosition {
305
315
// / If \p IRP is a call site (see isAnyCallSitePosition()) then the result
306
316
// / will be a call site position, otherwise the function position of the
307
317
// / associated function.
308
- static const IRPosition function_scope (const IRPosition &IRP) {
318
+ static const IRPosition
319
+ function_scope (const IRPosition &IRP,
320
+ const CallBaseContext *CBContext = nullptr ) {
309
321
if (IRP.isAnyCallSitePosition ()) {
310
322
return IRPosition::callsite_function (
311
323
cast<CallBase>(IRP.getAnchorValue ()));
312
324
}
313
325
assert (IRP.getAssociatedFunction ());
314
- return IRPosition::function (*IRP.getAssociatedFunction ());
326
+ return IRPosition::function (*IRP.getAssociatedFunction (), CBContext );
315
327
}
316
328
317
- bool operator ==(const IRPosition &RHS) const { return Enc == RHS.Enc ; }
329
+ bool operator ==(const IRPosition &RHS) const {
330
+ return Enc == RHS.Enc && RHS.CBContext == CBContext;
331
+ }
318
332
bool operator !=(const IRPosition &RHS) const { return !(*this == RHS); }
319
333
320
334
// / Return the value this abstract attribute is anchored with.
@@ -535,6 +549,19 @@ struct IRPosition {
535
549
}
536
550
}
537
551
552
+ // / Return the same position without the call base context.
553
+ IRPosition stripCallBaseContext () const {
554
+ IRPosition Result = *this ;
555
+ Result.CBContext = nullptr ;
556
+ return Result;
557
+ }
558
+
559
+ // / Get the call base context from the position.
560
+ const CallBaseContext *getCallBaseContext () const { return CBContext; }
561
+
562
+ // / Check if the position has any call base context.
563
+ bool hasCallBaseContext () const { return CBContext != nullptr ; }
564
+
538
565
// / Special DenseMap key values.
539
566
// /
540
567
// /{
@@ -547,10 +574,15 @@ struct IRPosition {
547
574
548
575
private:
549
576
// / Private constructor for special values only!
550
- explicit IRPosition (void *Ptr) { Enc.setFromOpaqueValue (Ptr); }
577
+ explicit IRPosition (void *Ptr, const CallBaseContext *CBContext = nullptr )
578
+ : CBContext(CBContext) {
579
+ Enc.setFromOpaqueValue (Ptr);
580
+ }
551
581
552
582
// / IRPosition anchored at \p AnchorVal with kind/argument numbet \p PK.
553
- explicit IRPosition (Value &AnchorVal, Kind PK) {
583
+ explicit IRPosition (Value &AnchorVal, Kind PK,
584
+ const CallBaseContext *CBContext = nullptr )
585
+ : CBContext(CBContext) {
554
586
switch (PK) {
555
587
case IRPosition::IRP_INVALID:
556
588
llvm_unreachable (" Cannot create invalid IRP with an anchor value!" );
@@ -672,16 +704,27 @@ struct IRPosition {
672
704
PointerIntPair<void *, NumEncodingBits, char > Enc;
673
705
// /}
674
706
707
+ // / Call base context. Used for callsite specific analysis.
708
+ const CallBaseContext *CBContext = nullptr ;
709
+
675
710
// / Return the encoding bits.
676
711
char getEncodingBits () const { return Enc.getInt (); }
677
712
};
678
713
679
714
// / Helper that allows IRPosition as a key in a DenseMap.
680
- template <> struct DenseMapInfo <IRPosition> : DenseMapInfo< void *> {
715
+ template <> struct DenseMapInfo <IRPosition> {
681
716
static inline IRPosition getEmptyKey () { return IRPosition::EmptyKey; }
682
717
static inline IRPosition getTombstoneKey () {
683
718
return IRPosition::TombstoneKey;
684
719
}
720
+ static unsigned getHashValue (const IRPosition &IRP) {
721
+ return (DenseMapInfo<void *>::getHashValue (IRP) << 4 ) ^
722
+ (DenseMapInfo<Value *>::getHashValue (IRP.getCallBaseContext ()));
723
+ }
724
+
725
+ static bool isEqual (const IRPosition &a, const IRPosition &b) {
726
+ return a == b;
727
+ }
685
728
};
686
729
687
730
// / A visitor class for IR positions.
@@ -1080,8 +1123,22 @@ struct Attributor {
1080
1123
// / NOTE: ForceUpdate is ignored in any stage other than the update stage.
1081
1124
template <typename AAType>
1082
1125
const AAType &
1083
- getOrCreateAAFor (const IRPosition & IRP, const AbstractAttribute *QueryingAA,
1126
+ getOrCreateAAFor (IRPosition IRP, const AbstractAttribute *QueryingAA,
1084
1127
DepClassTy DepClass, bool ForceUpdate = false ) {
1128
+ #ifdef EXPENSIVE_CHECKS
1129
+ // Don't allow callbase information to leak.
1130
+ if (auto CBContext = IRP.getCallBaseContext ()) {
1131
+ assert (
1132
+ ((CBContext->getCalledFunction () == IRP.getAnchorScope () ||
1133
+ QueryingAA ||
1134
+ !QueryingAA.getIRPosition ().isAnyCallSitePosition ())) &&
1135
+ " non callsite positions are not allowed to propagate CallBaseContext "
1136
+ " across functions" );
1137
+ }
1138
+ #endif
1139
+ if (!shouldPropagateCallBaseContext (IRP))
1140
+ IRP = IRP.stripCallBaseContext ();
1141
+
1085
1142
if (AAType *AAPtr = lookupAAFor<AAType>(IRP, QueryingAA, DepClass)) {
1086
1143
if (ForceUpdate && Phase == AttributorPhase::UPDATE)
1087
1144
updateAA (*AAPtr);
@@ -1600,6 +1657,9 @@ struct Attributor {
1600
1657
const AbstractAttribute *QueryingAA,
1601
1658
bool &AllCallSitesKnown);
1602
1659
1660
+ // / Determine if CallBase context in \p IRP should be propagated.
1661
+ bool shouldPropagateCallBaseContext (const IRPosition &IRP);
1662
+
1603
1663
// / Apply all requested function signature rewrites
1604
1664
// / (\see registerFunctionSignatureRewrite) and return Changed if the module
1605
1665
// / was altered.
0 commit comments