@@ -1219,6 +1219,133 @@ module Make<LocationSig Location, InputSig<Location> Input> {
1219
1219
1220
1220
/** Holds if the `i`th node of basic block `bb` evaluates this guard. */
1221
1221
predicate hasCfgNode ( BasicBlock bb , int i ) ;
1222
+
1223
+ /** Gets the location of this guard. */
1224
+ Location getLocation ( ) ;
1225
+ }
1226
+
1227
+ /**
1228
+ * A logical conjunction guard.
1229
+ *
1230
+ * Guards are automatically lifted to conjunctions:
1231
+ *
1232
+ * ```csharp
1233
+ * // Example 1
1234
+ * if (x == "safe" && x == "safe")
1235
+ * {
1236
+ * sink(x); // guarded
1237
+ * }
1238
+ * else
1239
+ * {
1240
+ * sink(x); // unguarded
1241
+ * }
1242
+ *
1243
+ * // Example 2
1244
+ * if (x == "safe" && x != "safe2")
1245
+ * {
1246
+ * sink(x); // guarded
1247
+ * }
1248
+ * else
1249
+ * {
1250
+ * sink(x); // unguarded
1251
+ * }
1252
+ *
1253
+ * // Example 3
1254
+ * if (x != "safe" && x == "safe2")
1255
+ * {
1256
+ * sink(x); // guarded
1257
+ * }
1258
+ * else
1259
+ * {
1260
+ * sink(x); // unguarded
1261
+ * }
1262
+ *
1263
+ * // Example 4
1264
+ * if (x != "safe1" && x != "safe2")
1265
+ * {
1266
+ * sink(x); // unguarded
1267
+ * }
1268
+ * else
1269
+ * {
1270
+ * sink(x); // guarded
1271
+ * }
1272
+ * ```
1273
+ *
1274
+ * Examples 1--3 should normally be handled via the control-flow graph (CFG)
1275
+ * implementation, but they are included in our logic for completeness.
1276
+ *
1277
+ * Example 4, which does not come for free just from the CFG, requires that
1278
+ * logical conjunctions be modeled post-order in the CFG, as they will
1279
+ * otherwise not dominate their `else` branch.
1280
+ */
1281
+ class AndGuard extends Guard {
1282
+ /** Gets the left operand of this conjunction. */
1283
+ Guard getLeftOperand ( ) ;
1284
+
1285
+ /** Gets the right operand of this conjunction. */
1286
+ Guard getRightOperand ( ) ;
1287
+ }
1288
+
1289
+ /**
1290
+ * A logical disjunction guard.
1291
+ *
1292
+ * Guards are automatically lifted to disjunctions:
1293
+ *
1294
+ * ```csharp
1295
+ * // Example 1
1296
+ * if (x == "safe1" || x == "safe2")
1297
+ * {
1298
+ * sink(x); // guarded
1299
+ * }
1300
+ * else
1301
+ * {
1302
+ * sink(x); // unguarded
1303
+ * }
1304
+ *
1305
+ * // Example 2
1306
+ * if (x == "safe" || x != "safe2")
1307
+ * {
1308
+ * sink(x); // unguarded
1309
+ * }
1310
+ * else
1311
+ * {
1312
+ * sink(x); // guarded
1313
+ * }
1314
+ *
1315
+ * // Example 3
1316
+ * if (x != "safe" || x == "safe2")
1317
+ * {
1318
+ * sink(x); // unguarded
1319
+ * }
1320
+ * else
1321
+ * {
1322
+ * sink(x); // guarded
1323
+ * }
1324
+ *
1325
+ * // Example 4
1326
+ * if (x != "safe" || x != "safe")
1327
+ * {
1328
+ * sink(x); // unguarded
1329
+ * }
1330
+ * else
1331
+ * {
1332
+ * sink(x); // guarded
1333
+ * }
1334
+ * ```
1335
+ *
1336
+ * Examples 1--3 should normally be handled via the control-flow graph (CFG)
1337
+ * implementation, but they are included in our logic for completeness.
1338
+ *
1339
+ * Example 4, which does not come for free just from the CFG, requires that
1340
+ * logical disjunctions be modeled post-order in the CFG, as they will
1341
+ * otherwise not dominate their `else` branch.
1342
+ */
1343
+ class OrGuard extends Guard {
1344
+ /** Gets the left operand of this disjunction. */
1345
+ Guard getLeftOperand ( ) ;
1346
+
1347
+ /** Gets the right operand of this disjunction. */
1348
+ Guard getRightOperand ( ) ;
1222
1349
}
1223
1350
1224
1351
/** Holds if `guard` controls block `bb` upon evaluating to `branch`. */
@@ -1641,6 +1768,24 @@ module Make<LocationSig Location, InputSig<Location> Input> {
1641
1768
pragma [ nomagic]
1642
1769
private predicate guardChecksSsaDef ( DfInput:: Guard g , Definition def , boolean branch ) {
1643
1770
guardChecks ( g , DfInput:: getARead ( def ) , branch )
1771
+ or
1772
+ exists ( boolean branchLeft , boolean branchRight |
1773
+ // Automatically lift to conjunctions
1774
+ g =
1775
+ any ( DfInput:: AndGuard ag |
1776
+ guardChecksSsaDef ( ag .getLeftOperand ( ) , def , branchLeft ) and
1777
+ guardChecksSsaDef ( ag .getRightOperand ( ) , def , branchRight ) and
1778
+ branch = branchLeft .booleanOr ( branchRight )
1779
+ )
1780
+ or
1781
+ // Automatically lift to disjunctions
1782
+ g =
1783
+ any ( DfInput:: OrGuard og |
1784
+ guardChecksSsaDef ( og .getLeftOperand ( ) , def , branchLeft ) and
1785
+ guardChecksSsaDef ( og .getRightOperand ( ) , def , branchRight ) and
1786
+ branch = branchLeft .booleanAnd ( branchRight )
1787
+ )
1788
+ )
1644
1789
}
1645
1790
1646
1791
/** Gets a node that is safely guarded by the given guard check. */
0 commit comments