@@ -522,84 +522,173 @@ bool AvarBoundsInference::inferBounds(BoundsKey K, const AVarGraph &BKGraph,
522
522
return IsChanged;
523
523
}
524
524
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
+
525
564
void
526
565
AVarBoundsInfo::inferLowerBounds (ProgramInfo *PI) {
527
566
computeInvalidLowerBounds ();
528
567
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.
529
572
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;
531
578
for (BoundsKey BK : InvalidLowerBounds) {
532
579
std::set<BoundsKey> Pred;
533
580
LowerBoundGraph.getPredecessors (BK, Pred);
534
581
for (BoundsKey Seed : Pred) {
535
- if (Seed != 0 &&
582
+ if (Seed != InvalidLowerBoundKey &&
536
583
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.
537
586
InfLBs[Seed] = Seed;
538
- WorkList.push_back (Seed);
587
+ WorkList.push (Seed);
539
588
}
540
589
}
541
590
}
542
591
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.
545
597
for (BoundsKey InvLB : InvalidLowerBounds)
546
- WorkList.push_back (InvLB);
598
+ WorkList.push (InvLB);
547
599
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.
548
604
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.
549
612
std::set<BoundsKey> HasConflictingBounds;
613
+
550
614
while (!WorkList.empty ()) {
551
615
BoundsKey BK = WorkList.front ();
552
- WorkList.pop_front ();
616
+ WorkList.pop ();
553
617
554
618
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 ());
558
626
InfLBs[BK] = getFreshLowerBound (BK);
559
627
NeedFreshLB.insert (BK);
560
628
}
561
629
562
630
std::set<BoundsKey> Succ;
563
631
LowerBoundGraph.getSuccessors (BK, Succ);
564
632
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);
591
680
}
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);
599
688
}
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`.
602
689
}
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`.
603
692
}
604
693
}
605
694
@@ -619,7 +708,8 @@ BoundsKey AVarBoundsInfo::getFreshLowerBound(BoundsKey Arr) {
619
708
620
709
bool AVarBoundsInfo::hasLowerBound (BoundsKey K) {
621
710
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);
623
713
}
624
714
625
715
bool AvarBoundsInference::inferFromPotentialBounds (BoundsKey BK,
@@ -802,7 +892,8 @@ bool AVarBoundsInfo::tryGetVariable(clang::Expr *E, const ASTContext &C,
802
892
// Merging bounds B with the present bounds of key L at the same priority P
803
893
// Returns true if we update the bounds for L (with B)
804
894
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 ())
806
897
B->setLowerBoundKey (LowerBounds[L]);
807
898
bool RetVal = false ;
808
899
if (BInfo.find (L) != BInfo.end () && BInfo[L].find (P) != BInfo[L].end ()) {
@@ -1468,32 +1559,6 @@ void AVarBoundsInfo::performFlowAnalysis(ProgramInfo *PI) {
1468
1559
PStats.endArrayBoundsInferenceTime ();
1469
1560
}
1470
1561
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
- }
1497
1562
1498
1563
bool AVarBoundsInfo::keepHighestPriorityBounds () {
1499
1564
bool HasChanged = false ;
0 commit comments