@@ -80,7 +80,6 @@ module Make<LocationSig Location, InputSig<Location> Input> {
80
80
BasicBlock getAPredecessor ( SuccessorType t ) { result .getASuccessor ( t ) = this }
81
81
82
82
/** Gets the control flow node at a specific (zero-indexed) position in this basic block. */
83
- cached
84
83
Node getNode ( int pos ) { bbIndex ( this .getFirstNode ( ) , result , pos ) }
85
84
86
85
/** Gets a control flow node in this basic block. */
@@ -152,6 +151,60 @@ module Make<LocationSig Location, InputSig<Location> Input> {
152
151
*/
153
152
BasicBlock getImmediateDominator ( ) { bbIDominates ( result , this ) }
154
153
154
+ /**
155
+ * Holds if basic block `succ` is immediately controlled by this basic
156
+ * block with conditional value `s`. That is, `succ` is an immediate
157
+ * successor of this block, and `succ` can only be reached from
158
+ * the callable entry point by going via the `s` edge out of this basic block.
159
+ */
160
+ pragma [ nomagic]
161
+ predicate immediatelyControls ( BasicBlock succ , SuccessorType s ) {
162
+ succ = this .getASuccessor ( s ) and
163
+ forall ( BasicBlock pred | pred = succ .getAPredecessor ( ) and pred != this |
164
+ succ .dominates ( pred )
165
+ )
166
+ }
167
+
168
+ /**
169
+ * Holds if basic block `controlled` is controlled by this basic block with
170
+ * conditional value `s`. That is, `controlled` can only be reached from
171
+ * the callable entry point by going via the `s` edge out of this basic block.
172
+ */
173
+ predicate controls ( BasicBlock controlled , SuccessorType s ) {
174
+ // For this block to control the block `controlled` with `s` the following must be true:
175
+ // 1/ Execution must have passed through the test i.e. `this` must strictly dominate `controlled`.
176
+ // 2/ Execution must have passed through the `s` edge leaving `this`.
177
+ //
178
+ // Although "passed through the `s` edge" implies that `this.getASuccessor(s)` dominates `controlled`,
179
+ // the reverse is not true, as flow may have passed through another edge to get to `this.getASuccessor(s)`
180
+ // so we need to assert that `this.getASuccessor(s)` dominates `controlled` *and* that
181
+ // all predecessors of `this.getASuccessor(s)` are either `this` or dominated by `this.getASuccessor(s)`.
182
+ //
183
+ // For example, in the following C# snippet:
184
+ // ```csharp
185
+ // if (x)
186
+ // controlled;
187
+ // false_successor;
188
+ // uncontrolled;
189
+ // ```
190
+ // `false_successor` dominates `uncontrolled`, but not all of its predecessors are `this` (`if (x)`)
191
+ // or dominated by itself. Whereas in the following code:
192
+ // ```csharp
193
+ // if (x)
194
+ // while (controlled)
195
+ // also_controlled;
196
+ // false_successor;
197
+ // uncontrolled;
198
+ // ```
199
+ // the block `while controlled` is controlled because all of its predecessors are `this` (`if (x)`)
200
+ // or (in the case of `also_controlled`) dominated by itself.
201
+ //
202
+ // The additional constraint on the predecessors of the test successor implies
203
+ // that `this` strictly dominates `controlled` so that isn't necessary to check
204
+ // directly.
205
+ exists ( BasicBlock succ | this .immediatelyControls ( succ , s ) | succ .dominates ( controlled ) )
206
+ }
207
+
155
208
/**
156
209
* Holds if this basic block strictly post-dominates basic block `bb`.
157
210
*
@@ -188,6 +241,52 @@ module Make<LocationSig Location, InputSig<Location> Input> {
188
241
cached
189
242
newtype TBasicBlock = TBasicBlockStart ( Node cfn ) { startsBB ( cfn ) }
190
243
244
+ /** Holds if `cfn` starts a new basic block. */
245
+ private predicate startsBB ( Node cfn ) {
246
+ not exists ( nodeGetAPredecessor ( cfn , _) ) and exists ( nodeGetASuccessor ( cfn , _) )
247
+ or
248
+ nodeIsJoin ( cfn )
249
+ or
250
+ nodeIsBranch ( nodeGetAPredecessor ( cfn , _) )
251
+ or
252
+ // In cases such as
253
+ //
254
+ // ```rb
255
+ // if x and y
256
+ // foo
257
+ // else
258
+ // bar
259
+ // ```
260
+ //
261
+ // we have a CFG that looks like
262
+ //
263
+ // x --false--> [false] x and y --false--> bar
264
+ // \ |
265
+ // --true--> y --false--
266
+ // \
267
+ // --true--> [true] x and y --true--> foo
268
+ //
269
+ // and we want to ensure that both `foo` and `bar` start a new basic block.
270
+ exists ( nodeGetAPredecessor ( cfn , any ( SuccessorType s | successorTypeIsCondition ( s ) ) ) )
271
+ }
272
+
273
+ /**
274
+ * Holds if `succ` is a control flow successor of `pred` within
275
+ * the same basic block.
276
+ */
277
+ private predicate intraBBSucc ( Node pred , Node succ ) {
278
+ succ = nodeGetASuccessor ( pred , _) and
279
+ not startsBB ( succ )
280
+ }
281
+
282
+ /**
283
+ * Holds if `bbStart` is the first node in a basic block and `cfn` is the
284
+ * `i`th node in the same basic block.
285
+ */
286
+ cached
287
+ predicate bbIndex ( Node bbStart , Node cfn , int i ) =
288
+ shortestDistances( startsBB / 1 , intraBBSucc / 2 ) ( bbStart , cfn , i )
289
+
191
290
/**
192
291
* Holds if the first node of basic block `succ` is a control flow
193
292
* successor of the last node of basic block `pred`.
@@ -213,51 +312,6 @@ module Make<LocationSig Location, InputSig<Location> Input> {
213
312
214
313
private import Cached
215
314
216
- /** Holds if `cfn` starts a new basic block. */
217
- private predicate startsBB ( Node cfn ) {
218
- not exists ( nodeGetAPredecessor ( cfn , _) ) and exists ( nodeGetASuccessor ( cfn , _) )
219
- or
220
- nodeIsJoin ( cfn )
221
- or
222
- nodeIsBranch ( nodeGetAPredecessor ( cfn , _) )
223
- or
224
- // In cases such as
225
- //
226
- // ```rb
227
- // if x and y
228
- // foo
229
- // else
230
- // bar
231
- // ```
232
- //
233
- // we have a CFG that looks like
234
- //
235
- // x --false--> [false] x or y --false--> bar
236
- // \ |
237
- // --true--> y --false--
238
- // \
239
- // --true--> [true] x or y --true--> foo
240
- //
241
- // and we want to ensure that both `foo` and `bar` start a new basic block.
242
- exists ( nodeGetAPredecessor ( cfn , any ( SuccessorType s | successorTypeIsCondition ( s ) ) ) )
243
- }
244
-
245
- /**
246
- * Holds if `succ` is a control flow successor of `pred` within
247
- * the same basic block.
248
- */
249
- predicate intraBBSucc ( Node pred , Node succ ) {
250
- succ = nodeGetASuccessor ( pred , _) and
251
- not startsBB ( succ )
252
- }
253
-
254
- /**
255
- * Holds if `bbStart` is the first node in a basic block and `cfn` is the
256
- * `i`th node in the same basic block.
257
- */
258
- private predicate bbIndex ( Node bbStart , Node cfn , int i ) =
259
- shortestDistances( startsBB / 1 , intraBBSucc / 2 ) ( bbStart , cfn , i )
260
-
261
315
/** Holds if `bb` is an entry basic block. */
262
316
private predicate entryBB ( BasicBlock bb ) { nodeIsDominanceEntry ( bb .getFirstNode ( ) ) }
263
317
}
0 commit comments