@@ -467,7 +467,7 @@ One way to understand which functions form basic blocks is to consider the
467
467
successors of each instruction. If we have two instructions A and B, we say
468
468
that B is a * successor* of A if, after executing A, we can execute B without any
469
469
intervening instructions. For instance, in the example above, the loop
470
- initialization statement ` unsigned long int i.1 = 1 ` is a successor of
470
+ initialization statement ` unsigned int i.1 = 1 ` is a successor of
471
471
` unsigned long fac.1 = 1 ` . On the other hand, ` return fac.1 ` is not a successor
472
472
of ` unsigned long fac.1 = 1 ` : we always have to execute some other intermediate
473
473
statements to reach the return statement.
@@ -534,7 +534,7 @@ and \ref analyses-specific-analyses.
534
534
535
535
While control flow graphs are already quite useful for static analysis,
536
536
some techniques benefit from a further transformation to a
537
- representation know as ** static single assignment** , short ** SSA** . The
537
+ representation known as ** static single assignment** , short ** SSA** . The
538
538
point of this step is to ensure that we can talk about the entire history
539
539
of assignments to a given variable. This is achieved by renaming
540
540
variables again: whenever we assign to a variable, we * clone* this
@@ -1218,23 +1218,24 @@ a map that associates both `fac` and `i` to "not 0".
1218
1218
An abstract domain is a set $D$ (or, if you
1219
1219
prefer, a data type) with the following properties:
1220
1220
- There is a function merge that takes two elements of $D$ and returns
1221
- an element of $D$. This function is associative (merge(x, merge(y,z))
1222
- = merge(merge(x,y), z)), commutative (merge(x,y) = merge(y,x)) and
1223
- idempotent (merge(x,x) = x).
1224
- - There is an element bottom of $D$ such that merge(x, bottom) = x.
1221
+ an element of $D$. This function is:
1222
+ * ** associative** - ` (merge(x, merge(y,z)) = merge(merge(x,y), z)) ` ,
1223
+ * ** commutative** - ` (merge(x,y) = merge(y,x)) ` and
1224
+ * ** idempotent** ` (merge(x,x) = x) ` .
1225
+ - There is an element bottom of $D$ such that ` merge(x, bottom) = x ` .
1225
1226
1226
1227
Algebraically speaking, $D$ needs to be a semi-lattice.
1227
1228
1228
1229
For our example, we use the following domain:
1229
1230
- D contains the elements "bottom" (nothing is known),
1230
1231
"equals 0", "not 0" and "could be 0".
1231
1232
1232
- - merge is defined as follows:
1233
- merge(bottom, x) = x
1234
- merge("could be 0", x) = "could be 0"
1235
- merge(x,x) = x
1236
- merge("equals 0", "not 0") = "could be 0"
1237
- - bottom is bottom, obviously.
1233
+ - ` merge ` is defined as follows:
1234
+ * ` merge(bottom, x) ` = ` x `
1235
+ * ` merge("could be 0", x) ` = ` "could be 0" `
1236
+ * ` merge(x,x) = ` x`
1237
+ * ` merge("equals 0", "not 0") ` = ` "could be 0" `
1238
+ - ` bottom ` is bottom, obviously.
1238
1239
It is easy but tedious to check that all conditions hold.
1239
1240
1240
1241
The second ingredient we need are the ** abstract state transformers** .
@@ -1251,7 +1252,7 @@ case, the result is "could be 0".
1251
1252
1252
1253
What if ` x ` and ` y ` are both "not 0"? In a mathematically ideal world,
1253
1254
we would have ` x*y ` be non-zero as well. But in a C program,
1254
- multiplication could overflow, yielding 0! So, to be correct, we have to
1255
+ multiplication could * overflow* , yielding ` 0 ` . So, to be correct, we have to
1255
1256
yield "could be 0" in this case.
1256
1257
1257
1258
Finally, when ` x ` is bottom, we can just return whatever value we had
0 commit comments