@@ -9496,115 +9496,180 @@ struct AACallEdgesFunction : public AACallEdgesImpl {
9496
9496
};
9497
9497
9498
9498
struct AAFunctionReachabilityFunction : public AAFunctionReachability {
9499
- AAFunctionReachabilityFunction (const IRPosition &IRP, Attributor &A)
9500
- : AAFunctionReachability(IRP, A) {}
9499
+ private:
9500
+ struct QuerySet {
9501
+ void markReachable (Function *Fn) {
9502
+ Reachable.insert (Fn);
9503
+ Unreachable.erase (Fn);
9504
+ }
9505
+
9506
+ ChangeStatus update (Attributor &A, const AAFunctionReachability &AA,
9507
+ ArrayRef<const AACallEdges *> AAEdgesList) {
9508
+ ChangeStatus Change = ChangeStatus::UNCHANGED;
9509
+
9510
+ for (auto *AAEdges : AAEdgesList) {
9511
+ if (AAEdges->hasUnknownCallee ()) {
9512
+ if (!CanReachUnknownCallee)
9513
+ Change = ChangeStatus::CHANGED;
9514
+ CanReachUnknownCallee = true ;
9515
+ return Change;
9516
+ }
9517
+ }
9501
9518
9502
- bool canReach (Attributor &A, Function *Fn) const override {
9503
- // Assume that we can reach any function if we can reach a call with
9504
- // unknown callee.
9505
- if (CanReachUnknownCallee)
9506
- return true ;
9519
+ for (Function *Fn : make_early_inc_range (Unreachable)) {
9520
+ if (checkIfReachable (A, AA, AAEdgesList, Fn)) {
9521
+ Change = ChangeStatus::CHANGED;
9522
+ markReachable (Fn);
9523
+ }
9524
+ }
9525
+ return Change;
9526
+ }
9507
9527
9508
- if (ReachableQueries.count (Fn))
9509
- return true ;
9528
+ bool isReachable (Attributor &A, const AAFunctionReachability &AA,
9529
+ ArrayRef<const AACallEdges *> AAEdgesList, Function *Fn) {
9530
+ // Assume that we can reach the function.
9531
+ // TODO: Be more specific with the unknown callee.
9532
+ if (CanReachUnknownCallee)
9533
+ return true ;
9534
+
9535
+ if (Reachable.count (Fn))
9536
+ return true ;
9537
+
9538
+ if (Unreachable.count (Fn))
9539
+ return false ;
9540
+
9541
+ // We need to assume that this function can't reach Fn to prevent
9542
+ // an infinite loop if this function is recursive.
9543
+ Unreachable.insert (Fn);
9544
+
9545
+ bool Result = checkIfReachable (A, AA, AAEdgesList, Fn);
9546
+ if (Result)
9547
+ markReachable (Fn);
9548
+ return Result;
9549
+ }
9550
+
9551
+ bool checkIfReachable (Attributor &A, const AAFunctionReachability &AA,
9552
+ ArrayRef<const AACallEdges *> AAEdgesList,
9553
+ Function *Fn) const {
9554
+
9555
+ // Handle the most trivial case first.
9556
+ for (auto *AAEdges : AAEdgesList) {
9557
+ const SetVector<Function *> &Edges = AAEdges->getOptimisticEdges ();
9558
+
9559
+ if (Edges.count (Fn))
9560
+ return true ;
9561
+ }
9562
+
9563
+ SmallVector<const AAFunctionReachability *, 8 > Deps;
9564
+ for (auto &AAEdges : AAEdgesList) {
9565
+ const SetVector<Function *> &Edges = AAEdges->getOptimisticEdges ();
9566
+
9567
+ for (Function *Edge : Edges) {
9568
+ // We don't need a dependency if the result is reachable.
9569
+ const AAFunctionReachability &EdgeReachability =
9570
+ A.getAAFor <AAFunctionReachability>(
9571
+ AA, IRPosition::function (*Edge), DepClassTy::NONE);
9572
+ Deps.push_back (&EdgeReachability);
9573
+
9574
+ if (EdgeReachability.canReach (A, Fn))
9575
+ return true ;
9576
+ }
9577
+ }
9578
+
9579
+ // The result is false for now, set dependencies and leave.
9580
+ for (auto Dep : Deps)
9581
+ A.recordDependence (AA, *Dep, DepClassTy::REQUIRED);
9510
9582
9511
- if (UnreachableQueries.count (Fn))
9512
9583
return false ;
9584
+ }
9585
+
9586
+ // / Set of functions that we know for sure is reachable.
9587
+ DenseSet<Function *> Reachable;
9588
+
9589
+ // / Set of functions that are unreachable, but might become reachable.
9590
+ DenseSet<Function *> Unreachable;
9513
9591
9592
+ // / If we can reach a function with a call to a unknown function we assume
9593
+ // / that we can reach any function.
9594
+ bool CanReachUnknownCallee = false ;
9595
+ };
9596
+
9597
+ public:
9598
+ AAFunctionReachabilityFunction (const IRPosition &IRP, Attributor &A)
9599
+ : AAFunctionReachability(IRP, A) {}
9600
+
9601
+ bool canReach (Attributor &A, Function *Fn) const override {
9514
9602
const AACallEdges &AAEdges =
9515
9603
A.getAAFor <AACallEdges>(*this , getIRPosition (), DepClassTy::REQUIRED);
9516
9604
9517
- const SetVector<Function *> &Edges = AAEdges.getOptimisticEdges ();
9518
- bool Result = checkIfReachable (A, Edges, Fn);
9605
+ // Attributor returns attributes as const, so this function has to be
9606
+ // const for users of this attribute to use it without having to do
9607
+ // a const_cast.
9608
+ // This is a hack for us to be able to cache queries.
9609
+ auto *NonConstThis = const_cast <AAFunctionReachabilityFunction *>(this );
9610
+ bool Result =
9611
+ NonConstThis->WholeFunction .isReachable (A, *this , {&AAEdges}, Fn);
9612
+
9613
+ return Result;
9614
+ }
9615
+
9616
+ // / Can \p CB reach \p Fn
9617
+ bool canReach (Attributor &A, CallBase &CB, Function *Fn) const override {
9618
+ const AACallEdges &AAEdges = A.getAAFor <AACallEdges>(
9619
+ *this , IRPosition::callsite_function (CB), DepClassTy::REQUIRED);
9519
9620
9520
9621
// Attributor returns attributes as const, so this function has to be
9521
9622
// const for users of this attribute to use it without having to do
9522
9623
// a const_cast.
9523
9624
// This is a hack for us to be able to cache queries.
9524
9625
auto *NonConstThis = const_cast <AAFunctionReachabilityFunction *>(this );
9626
+ QuerySet &CBQuery = NonConstThis->CBQueries [&CB];
9525
9627
9526
- if (Result)
9527
- NonConstThis->ReachableQueries .insert (Fn);
9528
- else
9529
- NonConstThis->UnreachableQueries .insert (Fn);
9628
+ bool Result = CBQuery.isReachable (A, *this , {&AAEdges}, Fn);
9530
9629
9531
9630
return Result;
9532
9631
}
9533
9632
9534
9633
// / See AbstractAttribute::updateImpl(...).
9535
9634
ChangeStatus updateImpl (Attributor &A) override {
9536
- if (CanReachUnknownCallee)
9537
- return ChangeStatus::UNCHANGED;
9538
-
9539
9635
const AACallEdges &AAEdges =
9540
9636
A.getAAFor <AACallEdges>(*this , getIRPosition (), DepClassTy::REQUIRED);
9541
- const SetVector<Function *> &Edges = AAEdges.getOptimisticEdges ();
9542
9637
ChangeStatus Change = ChangeStatus::UNCHANGED;
9543
9638
9544
- if (AAEdges.hasUnknownCallee ()) {
9545
- bool OldCanReachUnknown = CanReachUnknownCallee;
9546
- CanReachUnknownCallee = true ;
9547
- return OldCanReachUnknown ? ChangeStatus::UNCHANGED
9548
- : ChangeStatus::CHANGED;
9549
- }
9639
+ Change |= WholeFunction.update (A, *this , {&AAEdges});
9550
9640
9551
- // Check if any of the unreachable functions become reachable.
9552
- for (auto Current = UnreachableQueries.begin ();
9553
- Current != UnreachableQueries.end ();) {
9554
- if (!checkIfReachable (A, Edges, *Current)) {
9555
- Current++;
9556
- continue ;
9557
- }
9558
- ReachableQueries.insert (*Current);
9559
- UnreachableQueries.erase (*Current++);
9560
- Change = ChangeStatus::CHANGED;
9641
+ for (auto CBPair : CBQueries) {
9642
+ const AACallEdges &AAEdges = A.getAAFor <AACallEdges>(
9643
+ *this , IRPosition::callsite_function (*CBPair.first ),
9644
+ DepClassTy::REQUIRED);
9645
+
9646
+ Change |= CBPair.second .update (A, *this , {&AAEdges});
9561
9647
}
9562
9648
9563
9649
return Change;
9564
9650
}
9565
9651
9566
9652
const std::string getAsStr () const override {
9567
- size_t QueryCount = ReachableQueries.size () + UnreachableQueries.size ();
9653
+ size_t QueryCount =
9654
+ WholeFunction.Reachable .size () + WholeFunction.Unreachable .size ();
9568
9655
9569
- return " FunctionReachability [" + std::to_string (ReachableQueries.size ()) +
9570
- " ," + std::to_string (QueryCount) + " ]" ;
9656
+ return " FunctionReachability [" +
9657
+ std::to_string (WholeFunction.Reachable .size ()) + " ," +
9658
+ std::to_string (QueryCount) + " ]" ;
9571
9659
}
9572
9660
9573
9661
void trackStatistics () const override {}
9574
-
9575
9662
private:
9576
- bool canReachUnknownCallee () const override { return CanReachUnknownCallee; }
9577
-
9578
- bool checkIfReachable (Attributor &A, const SetVector<Function *> &Edges,
9579
- Function *Fn) const {
9580
- if (Edges.count (Fn))
9581
- return true ;
9582
-
9583
- for (Function *Edge : Edges) {
9584
- // We don't need a dependency if the result is reachable.
9585
- const AAFunctionReachability &EdgeReachability =
9586
- A.getAAFor <AAFunctionReachability>(*this , IRPosition::function (*Edge),
9587
- DepClassTy::NONE);
9588
-
9589
- if (EdgeReachability.canReach (A, Fn))
9590
- return true ;
9591
- }
9592
- for (Function *Fn : Edges)
9593
- A.getAAFor <AAFunctionReachability>(*this , IRPosition::function (*Fn),
9594
- DepClassTy::REQUIRED);
9595
-
9596
- return false ;
9663
+ bool canReachUnknownCallee () const override {
9664
+ return WholeFunction.CanReachUnknownCallee ;
9597
9665
}
9598
9666
9599
- // / Set of functions that we know for sure is reachable.
9600
- SmallPtrSet<Function *, 8 > ReachableQueries;
9601
-
9602
- // / Set of functions that are unreachable, but might become reachable.
9603
- SmallPtrSet<Function *, 8 > UnreachableQueries;
9667
+ // / Used to answer if a the whole function can reacha a specific function.
9668
+ QuerySet WholeFunction;
9604
9669
9605
- // / If we can reach a function with a call to a unknown function we assume
9606
- // / that we can reach any function.
9607
- bool CanReachUnknownCallee = false ;
9670
+ // / Used to answer if a call base inside this function can reach a specific
9671
+ // / function.
9672
+ DenseMap<CallBase *, QuerySet> CBQueries ;
9608
9673
};
9609
9674
9610
9675
} // namespace
0 commit comments