Skip to content

Commit bb04cde

Browse files
comments
1 parent abdb844 commit bb04cde

File tree

2 files changed

+139
-74
lines changed

2 files changed

+139
-74
lines changed

clang/include/clang/3C/AVarBoundsInfo.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ class AVarBoundsInfo {
395395
CtxSensitiveBoundsKeyHandler CSBKeyHandler;
396396

397397
AVarGraph LowerBoundGraph;
398-
static const BoundsKey InvalidLowerBoundKey = 0;
398+
const BoundsKey InvalidLowerBoundKey = 0;
399399

400400
// BoundsKeys that that cannot be used as a lower bound. These are used in an
401401
// update such as `a = a + 1`, or are transitively assigned from such a

clang/lib/3C/AVarBoundsInfo.cpp

Lines changed: 138 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -522,84 +522,173 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, const AVarGraph &BKGraph,
522522
return IsChanged;
523523
}
524524

525+
526+
void AVarBoundsInfo::computeInvalidLowerBounds() {
527+
// This will compute a breadth first search starting from the constant
528+
// InvalidLowerBoundKey. Any reachable keys are also invalid lower bounds.
529+
// This is essentially the same algorithm as is used for solving the checked
530+
// type constraint graph.
531+
assert(InvalidLowerBounds.empty());
532+
std::queue<BoundsKey> WorkList;
533+
WorkList.push(InvalidLowerBoundKey);
534+
535+
// To check if a bounds key is already invalidated we check if it is either in
536+
// the set of invalidated keys, or is the constant InvalidLowerBoundKey.
537+
auto IsInvalidated = [this](BoundsKey BK) {
538+
return BK == InvalidLowerBoundKey ||
539+
InvalidLowerBounds.find(BK) != InvalidLowerBounds.end();
540+
};
541+
542+
while (!WorkList.empty()) {
543+
BoundsKey Curr = WorkList.front();
544+
WorkList.pop();
545+
assert(IsInvalidated(Curr));
546+
547+
std::set<BoundsKey> Neighbors;
548+
LowerBoundGraph.getSuccessors(Curr, Neighbors);
549+
for (BoundsKey NK : Neighbors) {
550+
// The neighbors of an invalid lower bound are also invalid, with the
551+
// exception that if there is a bound in the source code, then we assume
552+
// the bound is correct, and so the pointer is a valid lower bound for
553+
// itself.
554+
bool HasDeclaredBounds =
555+
getBounds(NK, BoundsPriority::Declared) != nullptr;
556+
if (!HasDeclaredBounds && !IsInvalidated(NK)) {
557+
InvalidLowerBounds.insert(NK);
558+
WorkList.push(NK);
559+
}
560+
}
561+
}
562+
}
563+
525564
void
526565
AVarBoundsInfo::inferLowerBounds(ProgramInfo *PI) {
527566
computeInvalidLowerBounds();
528567

568+
// This maps array pointers to a single consistent lower bound pointer, or
569+
// possible the constant InvalidLowerBoundKey if no lower bound could be found
570+
// or generated. Note that there can only be a single valid lower bound.
571+
// Future work can extend this map to track sets if possible lower bounds.
529572
std::map<BoundsKey, BoundsKey> InfLBs;
530-
std::deque<BoundsKey> WorkList;
573+
574+
// Lower bound inference will proceed as a traversal of the LowerBoundGraph.
575+
// The traversal starts at the direct predecessors of the pointers that need
576+
// an inferred lower bound.
577+
std::queue<BoundsKey> WorkList;
531578
for (BoundsKey BK : InvalidLowerBounds) {
532579
std::set<BoundsKey> Pred;
533580
LowerBoundGraph.getPredecessors(BK, Pred);
534581
for (BoundsKey Seed : Pred) {
535-
if (Seed != 0 &&
582+
if (Seed != InvalidLowerBoundKey &&
536583
InvalidLowerBounds.find(Seed) == InvalidLowerBounds.end()) {
584+
// This pointer is a valid lower bound for itself, so add it to the
585+
// worklist and initialize it in the map of inferred lower bounds.
537586
InfLBs[Seed] = Seed;
538-
WorkList.push_back(Seed);
587+
WorkList.push(Seed);
539588
}
540589
}
541590
}
542591

543-
// These must come after the valid Lower Bounds in the worklist, so this loop
544-
// needs to be separate.
592+
// It's possible for there to be invalid lower bounds that are not reachable
593+
// from any valid lower bounds, so we also initialize the worklist with all
594+
// invalid lower bounds. These come after the valid lower bounds so that is
595+
// less likely a fresh lower bound will be generated but later thrown out, as
596+
// that process is inefficient at least in the current implementation.
545597
for (BoundsKey InvLB : InvalidLowerBounds)
546-
WorkList.push_back(InvLB);
598+
WorkList.push(InvLB);
547599

600+
// This set tracks the pointers for which we will need to generate a fresh
601+
// lower bound pointer. These pointers do not have a single consistent lower
602+
// bound in the source code, but 3C is able to insert a duplicate declaration
603+
// to act as the lower bound.
548604
std::set<BoundsKey> NeedFreshLB;
605+
606+
// This set track the pointers that have multiple inconsistent lower bounds.
607+
// This is used to differentiate pointers that need a fresh lower bound
608+
// because no lower bounds could be found from pointers that need a fresh
609+
// lower bound because there were multiple inconsistent lower bounds. Note
610+
// that is not a subset of NeedFreshLB because a pointer may have conflicting
611+
// bounds but be ineligible for a fresh lower bound.
549612
std::set<BoundsKey> HasConflictingBounds;
613+
550614
while (!WorkList.empty()) {
551615
BoundsKey BK = WorkList.front();
552-
WorkList.pop_front();
616+
WorkList.pop();
553617

554618
if (isEligibleForFreshLowerBound(BK) &&
555-
(InfLBs.find(BK) == InfLBs.end() || InfLBs[BK] == 0)) {
556-
// We've reached an array pointer in the work list that either has not been assigned a lower bound, or
557-
assert(InvalidLowerBounds.find(BK) != InvalidLowerBounds.end());
619+
(InfLBs.find(BK) == InfLBs.end() || InfLBs[BK] == InvalidLowerBoundKey)) {
620+
// We've reached an array pointer in the work list that either has not
621+
// been assigned a lower bound, or has multiple conflicting lower bounds.
622+
// We will generate a fresh lower bound.
623+
assert(
624+
"Generating fresh bound for pointer that can be its own lower bound." &&
625+
InvalidLowerBounds.find(BK) != InvalidLowerBounds.end());
558626
InfLBs[BK] = getFreshLowerBound(BK);
559627
NeedFreshLB.insert(BK);
560628
}
561629

562630
std::set<BoundsKey> Succ;
563631
LowerBoundGraph.getSuccessors(BK, Succ);
564632
for (BoundsKey S : Succ) {
565-
if (InvalidLowerBounds.find(S) != InvalidLowerBounds.end()) {
566-
if (InfLBs.find(S) == InfLBs.end()) {
567-
// No prior lower bound known for `S`. Initialize it to use the same
568-
// lower bound as `BK`.
569-
if (isInAccessibleScope(S, InfLBs[BK])) {
570-
InfLBs[S] = InfLBs[BK];
571-
} else {
572-
InfLBs[S] = 0;
573-
}
574-
WorkList.push_front(S);
575-
} else if (InfLBs[BK] != InfLBs[S] &&
576-
HasConflictingBounds.find(S) == HasConflictingBounds.end()) {
577-
HasConflictingBounds.insert(S);
578-
if (NeedFreshLB.find(S) != NeedFreshLB.end() &&
579-
isInAccessibleScope(S, InfLBs[BK])) {
580-
NeedFreshLB.erase(S);
581-
BoundsKey SLB = InfLBs[S];
582-
LowerBoundGraph.visitBreadthFirst(S, [this, SLB, &InfLBs, &WorkList](BoundsKey BK) {
583-
if (InfLBs.find(BK) != InfLBs.end() && InfLBs[BK] == SLB) {
584-
InfLBs.erase(BK);
585-
std::set<BoundsKey> Pred;
586-
LowerBoundGraph.getPredecessors(BK, Pred);
587-
for (BoundsKey P : Pred) {
588-
if (P != 0 && InfLBs.find(P) != InfLBs.end())
589-
WorkList.push_back(P);
590-
}
633+
634+
// Do not process any array pointers that are valid lower bounds. They
635+
// should just serve as their own lower bound.
636+
if (InvalidLowerBounds.find(S) == InvalidLowerBounds.end())
637+
continue;
638+
639+
if (InfLBs.find(S) == InfLBs.end()) {
640+
// No prior lower bound known for `S`. Initialize it to use the same
641+
// lower bound as `BK`, if this is possible given their scopes.
642+
if (isInAccessibleScope(S, InfLBs[BK])) {
643+
InfLBs[S] = InfLBs[BK];
644+
} else {
645+
InfLBs[S] = InvalidLowerBoundKey;
646+
}
647+
WorkList.push(S);
648+
} else if (InfLBs[BK] != InfLBs[S] &&
649+
HasConflictingBounds.find(S) == HasConflictingBounds.end()) {
650+
// The lower bound of `BK` is not the same as the current inferred lower
651+
// bounds of `S`. This is a problem, so we need to mark `S` as having
652+
// conflicting lower bounds. We only do this invalidation step once. If
653+
// the BoundsKey is already known to have conflicting bounds, then do
654+
// not reset it again. Doing so can cause an infinite loop when there is
655+
// a cycle of BoundsKeys needing a lower bound, where each BoundsKey in
656+
// the cycle is eligible for a fresh lower bound.
657+
HasConflictingBounds.insert(S);
658+
659+
if (NeedFreshLB.find(S) != NeedFreshLB.end() ) {
660+
// This case handles when we a fresh lower bounds was created for `S`
661+
// before any conflict was detected. It is possible that the conflict
662+
// we detect here only exists between the fresh lower bound and the
663+
// lower bound of `BK`. In this case, we can drop the fresh lower
664+
// bounds to use the inferred lower bound. In order to fully drop the
665+
// fresh bound, we must also drop it from all BoundsKey reachable from
666+
// `S`, as these may have already had a lower bound inferred based on
667+
// the fresh lower bound.
668+
NeedFreshLB.erase(S);
669+
BoundsKey SLB = InfLBs[S];
670+
// TODO: This is inefficient.
671+
LowerBoundGraph.visitBreadthFirst(S, [this, SLB, &InfLBs, &WorkList](BoundsKey BK) {
672+
if (InfLBs.find(BK) != InfLBs.end() && InfLBs[BK] == SLB) {
673+
InfLBs.erase(BK);
674+
std::set<BoundsKey> Pred;
675+
LowerBoundGraph.getPredecessors(BK, Pred);
676+
for (BoundsKey P : Pred) {
677+
if (P != InvalidLowerBoundKey &&
678+
InfLBs.find(P) != InfLBs.end())
679+
WorkList.push(P);
591680
}
592-
});
593-
} else if (InfLBs[S] != 0) {
594-
// If there is and existing lower bounds, it must be the same lower
595-
// bound as `BK`. If it's not, invalidate the lower bound for `S`.
596-
InfLBs[S] = 0;
597-
WorkList.push_back(S);
598-
}
681+
}
682+
});
683+
} else if (InfLBs[S] != InvalidLowerBoundKey) {
684+
// If no fresh lower bound was generated, then things are much
685+
// simpler. Just invalidate the lower bound of `S` and enqueue it.
686+
InfLBs[S] = InvalidLowerBoundKey;
687+
WorkList.push(S);
599688
}
600-
// Otherwise, the a lower bound exists for `S`, and it's the same lower
601-
// bounds as `BK`. Nothing changes, so don't enqueue `S`.
602689
}
690+
// Otherwise, the a lower bound exists for `S`, and it's the same lower
691+
// bounds as `BK`. Nothing changes, so don't enqueue `S`.
603692
}
604693
}
605694

@@ -619,7 +708,8 @@ BoundsKey AVarBoundsInfo::getFreshLowerBound(BoundsKey Arr) {
619708

620709
bool AVarBoundsInfo::hasLowerBound(BoundsKey K) {
621710
return InvalidLowerBounds.find(K) == InvalidLowerBounds.end() ||
622-
(LowerBounds.find(K) != LowerBounds.end() && LowerBounds[K] != 0);
711+
(LowerBounds.find(K) != LowerBounds.end() &&
712+
LowerBounds[K] != InvalidLowerBoundKey);
623713
}
624714

625715
bool AvarBoundsInference::inferFromPotentialBounds(BoundsKey BK,
@@ -802,7 +892,8 @@ bool AVarBoundsInfo::tryGetVariable(clang::Expr *E, const ASTContext &C,
802892
// Merging bounds B with the present bounds of key L at the same priority P
803893
// Returns true if we update the bounds for L (with B)
804894
bool AVarBoundsInfo::mergeBounds(BoundsKey L, BoundsPriority P, ABounds *B) {
805-
if (B->getLowerBoundKey() == 0 && LowerBounds.find(L) != LowerBounds.end())
895+
if (B->getLowerBoundKey() == InvalidLowerBoundKey &&
896+
LowerBounds.find(L) != LowerBounds.end())
806897
B->setLowerBoundKey(LowerBounds[L]);
807898
bool RetVal = false;
808899
if (BInfo.find(L) != BInfo.end() && BInfo[L].find(P) != BInfo[L].end()) {
@@ -1468,32 +1559,6 @@ void AVarBoundsInfo::performFlowAnalysis(ProgramInfo *PI) {
14681559
PStats.endArrayBoundsInferenceTime();
14691560
}
14701561

1471-
void AVarBoundsInfo::computeInvalidLowerBounds() {
1472-
assert(InvalidLowerBounds.empty());
1473-
std::queue<BoundsKey> WorkList;
1474-
WorkList.push(0);
1475-
1476-
auto IsInvalidated = [this](BoundsKey BK) {
1477-
return BK == 0 || InvalidLowerBounds.find(BK) != InvalidLowerBounds.end();
1478-
};
1479-
1480-
while (!WorkList.empty()) {
1481-
BoundsKey Curr = WorkList.front();
1482-
WorkList.pop();
1483-
assert(IsInvalidated(Curr));
1484-
1485-
std::set<BoundsKey> Neighbors;
1486-
LowerBoundGraph.getSuccessors(Curr, Neighbors);
1487-
for (BoundsKey NK : Neighbors) {
1488-
bool HasDeclaredBounds =
1489-
getBounds(NK, BoundsPriority::Declared) != nullptr;
1490-
if (!HasDeclaredBounds && !IsInvalidated(NK)) {
1491-
InvalidLowerBounds.insert(NK);
1492-
WorkList.push(NK);
1493-
}
1494-
}
1495-
}
1496-
}
14971562

14981563
bool AVarBoundsInfo::keepHighestPriorityBounds() {
14991564
bool HasChanged = false;

0 commit comments

Comments
 (0)