@@ -3749,74 +3749,98 @@ module ControlFlow {
37493749
37503750 /**
37513751 * Provides a predicate for the successor relation with split information,
3752- * `succSplits()`, as well as logic used to construct the type `TSplits`
3753- * representing sets of splits. Only sets of splits that can be reached
3754- * are constructed, hence the predicates are mutually recursive.
3752+ * as well as logic used to construct the type `TSplits` representing sets
3753+ * of splits. Only sets of splits that can be reached are constructed, hence
3754+ * the predicates are mutually recursive.
37553755 *
3756- * For the successor relation, we divide into two cases:
3756+ * For the successor relation
37573757 *
3758- * 1. The set of splits for the successor is the same as the set of splits
3759- * for the predecessor.
3760- * 2. The set of splits for the successor is different from the set of splits
3761- * for the predecessor.
3758+ * ```
3759+ * succSplits(ControlFlowElement pred, Splits predSplits, ControlFlowElement succ, Splits succSplits, Completion c)
3760+ * ```
37623761 *
3763- * These are further divided into :
3762+ * the following invariants are maintained :
37643763 *
3765- * 1a. The set of splits is the same because the successor is in the same
3766- * `SameSplitsBlock` block as the predecessor.
3767- * 1b. The set of splits is the same, but the successor is not in the same
3768- * `SameSplitsBlock` block as the predecessor.
3769- * 2a. The set of splits for the successor is *maybe* non-empty.
3770- * 2b. The set of splits for the successor is *always* empty.
3764+ * 1. `pred` is reachable with split set `predSplits`.
3765+ * 2. For all `split` in `predSplits`:
3766+ * - If `split.hasSuccessor(pred, succ, c)` then `split` in `succSplits`.
3767+ * 3. For all `split` in `predSplits`:
3768+ * - If `split.hasExit(pred, succ, c)` then `split` not in `succSplits`.
3769+ * 4. For all `split` not in `predSplits`:
3770+ * - If `split.hasEntry(pred, succ, c)` then `split` in `succSplits`.
3771+ * 5. For all `split` in `succSplits`:
3772+ * - `split.hasSuccessor(pred, succ, c)` and `split` in `predSplits`, or
3773+ * - `split.hasEntry(pred, succ, c)` and `split` not in `predSplits`.
3774+ *
3775+ * The algorithm divides into four cases:
3776+ *
3777+ * 1. The set of splits for the successor is the same as the set of splits
3778+ * for the predecessor:
3779+ * a) The successor is in the same `SameSplitsBlock` as the predecessor.
3780+ * b) The successor is *not* in the same `SameSplitsBlock` as the predecessor.
3781+ * 2. The set of splits for the successor is different from the set of splits
3782+ * for the predecessor:
3783+ * a) The set of splits for the successor is *maybe* non-empty.
3784+ * b) The set of splits for the successor is *always* empty.
37713785 *
37723786 * Only case 2a may introduce new sets of splits, so only predicates from
3773- * this case are used in the definition of `TSplits`.
3787+ * this case are used in the definition of `TSplits`.
37743788 *
37753789 * The predicates in this module are named after the cases above.
37763790 */
37773791 private module SuccSplits {
3778- private predicate succReachable ( Reachability:: SameSplitsBlock b , ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3792+ private predicate succInvariant1 ( Reachability:: SameSplitsBlock b , ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
37793793 pred = b .getAnElement ( ) and
37803794 b .isReachable ( predSplits ) and
37813795 succ = succ ( pred , c )
37823796 }
37833797
3784- private predicate succSplits1b0 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3798+ private predicate case1b0 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
37853799 exists ( Reachability:: SameSplitsBlock b |
3786- succReachable ( b , pred , predSplits , succ , c ) |
3800+ // Invariant 1
3801+ succInvariant1 ( b , pred , predSplits , succ , c ) |
37873802 ( succ = b .getAnElement ( ) implies succ = b ) and
3803+ // Invariant 4
37883804 not exists ( SplitInternal split | split .hasEntry ( pred , succ , c ) )
37893805 )
37903806 }
37913807
3792- // A `forall` over the splits in `predSplits`, but written using explicit recursion
3793- // to avoid negative recursion compilation error.
3794- private predicate succSplits1bForall ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , Splits remaining ) {
3795- succSplits1b0 ( pred , predSplits , succ , c ) and
3796- remaining = predSplits
3808+ /**
3809+ * Case 1b.
3810+ *
3811+ * Invariants 1 and 4 hold in the base case, and invariants 2, 3, and 5 are
3812+ * maintained for all splits in `predSplits` (= `succSplits`), except
3813+ * possibly for the splits in `except`.
3814+ *
3815+ * The predicate is written using explicit recursion, as opposed to a `forall`,
3816+ * to avoid negative recursion.
3817+ */
3818+ private predicate case1bForall ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , Splits except ) {
3819+ case1b0 ( pred , predSplits , succ , c ) and
3820+ except = predSplits
37973821 or
37983822 exists ( Splits mid , SplitInternal split |
3799- succSplits1bForall ( pred , predSplits , succ , c , mid ) |
3800- mid = TSplitsCons ( split , remaining ) and
3823+ case1bForall ( pred , predSplits , succ , c , mid ) |
3824+ mid = TSplitsCons ( split , except ) and
38013825 split .hasSuccessor ( pred , succ , c )
38023826 )
38033827 }
38043828
3805- private predicate succSplits1 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3829+ private predicate case1 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
38063830 // Case 1a
38073831 exists ( Reachability:: SameSplitsBlock b |
3808- succReachable ( b , pred , predSplits , succ , c ) |
3832+ succInvariant1 ( b , pred , predSplits , succ , c ) |
38093833 succ = b .getAnElement ( ) and
38103834 not succ = b
38113835 )
38123836 or
38133837 // Case 1b
3814- succSplits1bForall ( pred , predSplits , succ , c , TSplitsNil ( ) )
3838+ case1bForall ( pred , predSplits , succ , c , TSplitsNil ( ) )
38153839 }
38163840
3817- private predicate succSplits2aux ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3841+ private predicate case2aux ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
38183842 exists ( Reachability:: SameSplitsBlock b |
3819- succReachable ( b , pred , predSplits , succ , c ) and
3843+ succInvariant1 ( b , pred , predSplits , succ , c ) and
38203844 ( succ = b .getAnElement ( ) implies succ = b )
38213845 |
38223846 predSplits .getASplit ( ) .hasExit ( pred , succ , c )
@@ -3825,114 +3849,141 @@ module ControlFlow {
38253849 )
38263850 }
38273851
3828- // A `forall` over the splits in `predSplits`, but written using explicit recursion
3829- // to avoid negative recursion compilation error.
3830- private predicate succSplits2aNoneOfKindForall ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , SplitKind sk , Splits remaining ) {
3831- succSplits2aux ( pred , predSplits , succ , c ) and
3852+ /**
3853+ * Holds if `succSplits` should not inherit a split of kind `sk` from
3854+ * `predSplits, except possibly because of a split in `except`.
3855+ *
3856+ * The predicate is written using explicit recursion, as opposed to a `forall`,
3857+ * to avoid negative recursion.
3858+ */
3859+ private predicate case2aNoneInheritedOfKindForall ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , SplitKind sk , Splits except ) {
3860+ case2aux ( pred , predSplits , succ , c ) and
38323861 sk .appliesTo ( succ ) and
3833- remaining = predSplits
3862+ except = predSplits
38343863 or
38353864 exists ( Splits mid , SplitInternal split |
3836- succSplits2aNoneOfKindForall ( pred , predSplits , succ , c , sk , mid ) and
3837- mid = TSplitsCons ( split , remaining )
3865+ case2aNoneInheritedOfKindForall ( pred , predSplits , succ , c , sk , mid ) and
3866+ mid = TSplitsCons ( split , except )
38383867 |
3839- split .getKind ( ) = any ( SplitKind sk0 |
3840- sk0 != sk and
3841- ( sk0 .appliesTo ( succ ) or split .hasExit ( pred , succ , c ) )
3842- )
3868+ split .getKind ( ) = any ( SplitKind sk0 | sk0 != sk and sk0 .appliesTo ( succ ) )
38433869 or
38443870 split .hasExit ( pred , succ , c )
38453871 )
38463872 }
38473873
3874+ /** Holds if `succSplits` should not have a split of kind `sk`. */
38483875 pragma [ noinline]
3849- private predicate succSplits2aNoneOfKind ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , SplitKind sk ) {
3850- succSplits2aNoneOfKindForall ( pred , predSplits , succ , c , sk , TSplitsNil ( ) ) and
3876+ private predicate case2aNoneOfKind ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , SplitKind sk ) {
3877+ // None inherited from predecessor
3878+ case2aNoneInheritedOfKindForall ( pred , predSplits , succ , c , sk , TSplitsNil ( ) ) and
3879+ // None newly entered into
38513880 not exists ( SplitInternal split | split .hasEntry ( pred , succ , c ) | split .getKind ( ) = sk )
38523881 }
38533882
3883+ /** Holds if `succSplits` should not have a split of kind `sk` at rank `rnk`. */
38543884 pragma [ noinline]
3855- private predicate succSplits2aNoneAtRank ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , int rnk ) {
3885+ private predicate case2aNoneAtRank ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , int rnk ) {
38563886 exists ( SplitKind sk |
3857- succSplits2aNoneOfKind ( pred , predSplits , succ , c , sk ) |
3887+ case2aNoneOfKind ( pred , predSplits , succ , c , sk ) |
38583888 rnk = sk .getListRank ( succ )
38593889 )
38603890 }
38613891
3892+ /** Gets a split that should be in `succSplits`. */
38623893 pragma [ nomagic]
3863- private SplitInternal succSplits2aSome ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3864- succSplits2aux ( pred , predSplits , succ , c ) and
3894+ private SplitInternal case2aSome ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c ) {
3895+ case2aux ( pred , predSplits , succ , c ) and
38653896 (
38663897 result = predSplits .getASplit ( ) and
38673898 result .hasSuccessor ( pred , succ , c )
38683899 or
38693900 result .hasEntry ( pred , succ , c ) and
3870- succSplits2aNoneOfKindForall ( pred , predSplits , succ , c , result .getKind ( ) , TSplitsNil ( ) )
3901+ case2aNoneInheritedOfKindForall ( pred , predSplits , succ , c , result .getKind ( ) , TSplitsNil ( ) )
38713902 )
38723903 }
38733904
3874- SplitInternal succSplits2aSomeAtRank ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , int rnk ) {
3875- result = succSplits2aSome ( pred , predSplits , succ , c ) and
3905+ /** Gets a split that should be in `succSplits` at rank `rnk`. */
3906+ SplitInternal case2aSomeAtRank ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , int rnk ) {
3907+ result = case2aSome ( pred , predSplits , succ , c ) and
38763908 rnk = result .getKind ( ) .getListRank ( succ )
38773909 }
38783910
3879- predicate succSplits2a ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c , int rnk ) {
3880- succSplits2aux ( pred , predSplits , succ , c ) and
3911+ /**
3912+ * Case 2a.
3913+ *
3914+ * As opposed to the other cases, in this case we need to construct a new set
3915+ * of splits `succSplits`. Since this involves constructing the very IPA type,
3916+ * we cannot recurse directly over the structure of `succSplits`. Instead, we
3917+ * recurse over the ranks of all splits that *might* be in `succSplits`.
3918+ *
3919+ * - Invariant 1 holds in the base case,
3920+ * - invariant 2 holds for all splits with rank at least `rnk`,
3921+ * - invariant 3 holds for all splits in `predSplits`,
3922+ * - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`,
3923+ * and
3924+ * - invariant 4 holds for all splits in `succSplits` with rank at least `rnk`.
3925+ */
3926+ predicate case2aFromRank ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c , int rnk ) {
3927+ case2aux ( pred , predSplits , succ , c ) and
38813928 succSplits = TSplitsNil ( ) and
38823929 rnk = max ( any ( SplitKind sk ) .getListRank ( succ ) ) + 1
38833930 or
3884- succSplits2a ( pred , predSplits , succ , succSplits , c , rnk + 1 ) and
3885- succSplits2aNoneAtRank ( pred , predSplits , succ , c , rnk )
3931+ case2aFromRank ( pred , predSplits , succ , succSplits , c , rnk + 1 ) and
3932+ case2aNoneAtRank ( pred , predSplits , succ , c , rnk )
38863933 or
38873934 exists ( Splits mid , SplitInternal split |
3888- split = succSplits2aCons ( pred , predSplits , succ , mid , c , rnk ) |
3935+ split = case2aCons ( pred , predSplits , succ , mid , c , rnk ) |
38893936 succSplits = TSplitsCons ( split , mid )
38903937 )
38913938 }
38923939
38933940 pragma [ noinline]
3894- private SplitInternal succSplits2aCons ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c , int rnk ) {
3895- succSplits2a ( pred , predSplits , succ , succSplits , c , rnk + 1 ) and
3896- result = succSplits2aSomeAtRank ( pred , predSplits , succ , c , rnk )
3941+ private SplitInternal case2aCons ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c , int rnk ) {
3942+ case2aFromRank ( pred , predSplits , succ , succSplits , c , rnk + 1 ) and
3943+ result = case2aSomeAtRank ( pred , predSplits , succ , c , rnk )
38973944 }
38983945
3899- // A `forall` over the splits in `predSplits`, but written using explicit recursion
3900- // to avoid negative recursion compilation error.
3901- private predicate succSplits2b ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , Splits remaining ) {
3902- succSplits2aux ( pred , predSplits , succ , c ) and
3946+ /**
3947+ * Case 2b.
3948+ *
3949+ * Invariants 1, 4, and 5 hold in the base case, and invariants 2 and 3 are
3950+ * maintained for all splits in `predSplits`, except possibly for the splits
3951+ * in `except`.
3952+ *
3953+ * The predicate is written using explicit recursion, as opposed to a `forall`,
3954+ * to avoid negative recursion.
3955+ */
3956+ private predicate case2bForall ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , Splits except ) {
3957+ // Invariant 1
3958+ case2aux ( pred , predSplits , succ , c ) and
3959+ // Invariants 4 and 5
39033960 not any ( SplitKind sk ) .appliesTo ( succ ) and
3904- remaining = predSplits
3961+ except = predSplits
39053962 or
39063963 exists ( Splits mid , SplitInternal split |
3907- succSplits2b ( pred , predSplits , succ , c , mid ) |
3908- mid = TSplitsCons ( split , remaining ) and
3964+ case2bForall ( pred , predSplits , succ , c , mid ) |
3965+ mid = TSplitsCons ( split , except ) and
3966+ // Invariants 2 and 3
39093967 split .hasExit ( pred , succ , c )
39103968 )
39113969 }
39123970
3913- private predicate succSplits2 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c ) {
3914- // Case 2a
3915- succSplits2a ( pred , predSplits , succ , succSplits , c , 1 )
3971+ private predicate case2 ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c ) {
3972+ case2aFromRank ( pred , predSplits , succ , succSplits , c , 1 )
39163973 or
3917- // Case 2b
3918- succSplits2b ( pred , predSplits , succ , c , TSplitsNil ( ) ) and
3974+ case2bForall ( pred , predSplits , succ , c , TSplitsNil ( ) ) and
39193975 succSplits = TSplitsNil ( )
39203976 }
39213977
39223978 /**
39233979 * Holds if `succ` with splits `succSplits` is a successor of type `t` for `pred`
39243980 * with splits `predSplits`.
39253981 */
3926- predicate succSplits ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , SuccessorType t ) {
3927- exists ( Completion c |
3928- t .matchesCompletion ( c ) |
3929- // Case 1
3930- succSplits1 ( pred , predSplits , succ , c ) and
3931- succSplits = predSplits
3932- or
3933- // Case 2
3934- succSplits2 ( pred , predSplits , succ , succSplits , c )
3935- )
3982+ predicate succSplits ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Splits succSplits , Completion c ) {
3983+ case1 ( pred , predSplits , succ , c ) and
3984+ succSplits = predSplits
3985+ or
3986+ case2 ( pred , predSplits , succ , succSplits , c )
39363987 }
39373988 }
39383989 import SuccSplits
@@ -4069,8 +4120,8 @@ module ControlFlow {
40694120 or
40704121 TSplitsCons ( SplitInternal head , Splits tail ) {
40714122 exists ( ControlFlowElement pred , Splits predSplits , ControlFlowElement succ , Completion c , int rnk |
4072- succSplits2a ( pred , predSplits , succ , tail , c , rnk + 1 ) |
4073- head = succSplits2aSomeAtRank ( pred , predSplits , succ , c , rnk )
4123+ case2aFromRank ( pred , predSplits , succ , tail , c , rnk + 1 ) |
4124+ head = case2aSomeAtRank ( pred , predSplits , succ , c , rnk )
40744125 )
40754126 }
40764127
@@ -4152,9 +4203,10 @@ module ControlFlow {
41524203 succExitSplits ( predElement , predSplits , result .( Nodes:: ExitNode ) .getCallable ( ) , t )
41534204 or
41544205 // Element node -> element node
4155- exists ( ControlFlowElement succElement , Splits succSplits |
4206+ exists ( ControlFlowElement succElement , Splits succSplits , Completion c |
41564207 result = TElementNode ( succElement , succSplits ) |
4157- succSplits ( predElement , predSplits , succElement , succSplits , t )
4208+ succSplits ( predElement , predSplits , succElement , succSplits , c ) and
4209+ t .matchesCompletion ( c )
41584210 )
41594211 )
41604212 }
0 commit comments