Skip to content

Commit d75c9e6

Browse files
committed
[Attributor] Attributor call site specific AAValueConstantRange
This patch makes uses of the context bridges introduced in D83299 to make AAValueConstantRange call site specific. Reviewed By: jdoerfert Differential Revision: https://reviews.llvm.org/D83744
1 parent daf3699 commit d75c9e6

File tree

6 files changed

+471
-43
lines changed

6 files changed

+471
-43
lines changed

llvm/include/llvm/Transforms/IPO/Attributor.h

Lines changed: 76 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@ struct AADepGraph {
229229
/// are floating values that do not have a corresponding attribute list
230230
/// position.
231231
struct IRPosition {
232+
// NOTE: In the future this definition can be changed to support recursive
233+
// functions.
234+
using CallBaseContext = CallBase;
232235

233236
/// The positions we distinguish in the IR.
234237
enum Kind : char {
@@ -249,27 +252,34 @@ struct IRPosition {
249252
IRPosition() : Enc(nullptr, ENC_VALUE) { verify(); }
250253

251254
/// 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) {
253257
if (auto *Arg = dyn_cast<Argument>(&V))
254-
return IRPosition::argument(*Arg);
258+
return IRPosition::argument(*Arg, CBContext);
255259
if (auto *CB = dyn_cast<CallBase>(&V))
256260
return IRPosition::callsite_returned(*CB);
257-
return IRPosition(const_cast<Value &>(V), IRP_FLOAT);
261+
return IRPosition(const_cast<Value &>(V), IRP_FLOAT, CBContext);
258262
}
259263

260264
/// 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);
263269
}
264270

265271
/// 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);
268276
}
269277

270278
/// 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);
273283
}
274284

275285
/// Create a position describing the function scope of \p CB.
@@ -305,16 +315,20 @@ struct IRPosition {
305315
/// If \p IRP is a call site (see isAnyCallSitePosition()) then the result
306316
/// will be a call site position, otherwise the function position of the
307317
/// 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) {
309321
if (IRP.isAnyCallSitePosition()) {
310322
return IRPosition::callsite_function(
311323
cast<CallBase>(IRP.getAnchorValue()));
312324
}
313325
assert(IRP.getAssociatedFunction());
314-
return IRPosition::function(*IRP.getAssociatedFunction());
326+
return IRPosition::function(*IRP.getAssociatedFunction(), CBContext);
315327
}
316328

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+
}
318332
bool operator!=(const IRPosition &RHS) const { return !(*this == RHS); }
319333

320334
/// Return the value this abstract attribute is anchored with.
@@ -535,6 +549,19 @@ struct IRPosition {
535549
}
536550
}
537551

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+
538565
/// Special DenseMap key values.
539566
///
540567
///{
@@ -547,10 +574,15 @@ struct IRPosition {
547574

548575
private:
549576
/// 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+
}
551581

552582
/// 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) {
554586
switch (PK) {
555587
case IRPosition::IRP_INVALID:
556588
llvm_unreachable("Cannot create invalid IRP with an anchor value!");
@@ -672,16 +704,27 @@ struct IRPosition {
672704
PointerIntPair<void *, NumEncodingBits, char> Enc;
673705
///}
674706

707+
/// Call base context. Used for callsite specific analysis.
708+
const CallBaseContext *CBContext = nullptr;
709+
675710
/// Return the encoding bits.
676711
char getEncodingBits() const { return Enc.getInt(); }
677712
};
678713

679714
/// Helper that allows IRPosition as a key in a DenseMap.
680-
template <> struct DenseMapInfo<IRPosition> : DenseMapInfo<void *> {
715+
template <> struct DenseMapInfo<IRPosition> {
681716
static inline IRPosition getEmptyKey() { return IRPosition::EmptyKey; }
682717
static inline IRPosition getTombstoneKey() {
683718
return IRPosition::TombstoneKey;
684719
}
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+
}
685728
};
686729

687730
/// A visitor class for IR positions.
@@ -1080,8 +1123,22 @@ struct Attributor {
10801123
/// NOTE: ForceUpdate is ignored in any stage other than the update stage.
10811124
template <typename AAType>
10821125
const AAType &
1083-
getOrCreateAAFor(const IRPosition &IRP, const AbstractAttribute *QueryingAA,
1126+
getOrCreateAAFor(IRPosition IRP, const AbstractAttribute *QueryingAA,
10841127
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+
10851142
if (AAType *AAPtr = lookupAAFor<AAType>(IRP, QueryingAA, DepClass)) {
10861143
if (ForceUpdate && Phase == AttributorPhase::UPDATE)
10871144
updateAA(*AAPtr);
@@ -1600,6 +1657,9 @@ struct Attributor {
16001657
const AbstractAttribute *QueryingAA,
16011658
bool &AllCallSitesKnown);
16021659

1660+
/// Determine if CallBase context in \p IRP should be propagated.
1661+
bool shouldPropagateCallBaseContext(const IRPosition &IRP);
1662+
16031663
/// Apply all requested function signature rewrites
16041664
/// (\see registerFunctionSignatureRewrite) and return Changed if the module
16051665
/// was altered.

llvm/lib/Transforms/IPO/Attributor.cpp

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ static cl::opt<bool> PrintDependencies("attributor-print-dep", cl::Hidden,
142142
cl::desc("Print attribute dependencies"),
143143
cl::init(false));
144144

145+
static cl::opt<bool> EnableCallSiteSpecific(
146+
"attributor-enable-call-site-specific-deduction", cl::Hidden,
147+
cl::desc("Allow the Attributor to do call site specific analysis"),
148+
cl::init(false));
149+
145150
/// Logic operators for the change status enum class.
146151
///
147152
///{
@@ -476,6 +481,8 @@ void IRPosition::verify() {
476481
#ifdef EXPENSIVE_CHECKS
477482
switch (getPositionKind()) {
478483
case IRP_INVALID:
484+
assert((CBContext == nullptr) &&
485+
"Invalid position must not have CallBaseContext!");
479486
assert(!Enc.getOpaqueValue() &&
480487
"Expected a nullptr for an invalid position!");
481488
return;
@@ -491,12 +498,16 @@ void IRPosition::verify() {
491498
"Associated value mismatch!");
492499
return;
493500
case IRP_CALL_SITE_RETURNED:
501+
assert((CBContext == nullptr) &&
502+
"'call site returned' position must not have CallBaseContext!");
494503
assert((isa<CallBase>(getAsValuePtr())) &&
495504
"Expected call base for 'call site returned' position!");
496505
assert(getAsValuePtr() == &getAssociatedValue() &&
497506
"Associated value mismatch!");
498507
return;
499508
case IRP_CALL_SITE:
509+
assert((CBContext == nullptr) &&
510+
"'call site function' position must not have CallBaseContext!");
500511
assert((isa<CallBase>(getAsValuePtr())) &&
501512
"Expected call base for 'call site function' position!");
502513
assert(getAsValuePtr() == &getAssociatedValue() &&
@@ -515,6 +526,8 @@ void IRPosition::verify() {
515526
"Associated value mismatch!");
516527
return;
517528
case IRP_CALL_SITE_ARGUMENT: {
529+
assert((CBContext == nullptr) &&
530+
"'call site argument' position must not have CallBaseContext!");
518531
Use *U = getAsUsePtr();
519532
assert(U && "Expected use for a 'call site argument' position!");
520533
assert(isa<CallBase>(U->getUser()) &&
@@ -849,6 +862,13 @@ bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
849862
return true;
850863
}
851864

865+
bool Attributor::shouldPropagateCallBaseContext(const IRPosition &IRP) {
866+
// TODO: Maintain a cache of Values that are
867+
// on the pathway from a Argument to a Instruction that would effect the
868+
// liveness/return state etc.
869+
return EnableCallSiteSpecific;
870+
}
871+
852872
bool Attributor::checkForAllReturnedValuesAndReturnInsts(
853873
function_ref<bool(Value &, const SmallSetVector<ReturnInst *, 4> &)> Pred,
854874
const AbstractAttribute &QueryingAA) {
@@ -1125,6 +1145,9 @@ ChangeStatus Attributor::manifestAttributes() {
11251145
if (!State.isAtFixpoint())
11261146
State.indicateOptimisticFixpoint();
11271147

1148+
// We must not manifest Attributes that use Callbase info.
1149+
if (AA->hasCallBaseContext())
1150+
continue;
11281151
// If the state is invalid, we do not try to manifest it.
11291152
if (!State.isValidState())
11301153
continue;
@@ -2221,9 +2244,12 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) {
22212244

22222245
raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) {
22232246
const Value &AV = Pos.getAssociatedValue();
2224-
return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " ["
2225-
<< Pos.getAnchorValue().getName() << "@" << Pos.getCallSiteArgNo()
2226-
<< "]}";
2247+
OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " ["
2248+
<< Pos.getAnchorValue().getName() << "@" << Pos.getCallSiteArgNo() << "]";
2249+
2250+
if (Pos.hasCallBaseContext())
2251+
OS << "[cb_context:" << *Pos.getCallBaseContext() << "]";
2252+
return OS << "}";
22272253
}
22282254

22292255
raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) {

0 commit comments

Comments
 (0)