From f2e424944eee5fbdb639c6a3f4f75e3b68881ff3 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Wed, 13 Nov 2024 19:57:08 -0800 Subject: [PATCH] Start working on the control flow graphs post Signed-off-by: Danila Fedorin --- content/blog/00_spa_agda_intro.md | 4 +- content/blog/05_spa_agda_semantics/index.md | 1 + content/blog/06_spa_agda_cfg/if-cfg.dot | 15 ++ content/blog/06_spa_agda_cfg/if-cfg.png | Bin 0 -> 21067 bytes content/blog/06_spa_agda_cfg/index.md | 179 ++++++++++++++++++++ content/blog/06_spa_agda_cfg/while-cfg.dot | 15 ++ content/blog/06_spa_agda_cfg/while-cfg.png | Bin 0 -> 13927 bytes 7 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 content/blog/06_spa_agda_cfg/if-cfg.dot create mode 100644 content/blog/06_spa_agda_cfg/if-cfg.png create mode 100644 content/blog/06_spa_agda_cfg/index.md create mode 100644 content/blog/06_spa_agda_cfg/while-cfg.dot create mode 100644 content/blog/06_spa_agda_cfg/while-cfg.png diff --git a/content/blog/00_spa_agda_intro.md b/content/blog/00_spa_agda_intro.md index 1b9ff0e..175f258 100644 --- a/content/blog/00_spa_agda_intro.md +++ b/content/blog/00_spa_agda_intro.md @@ -104,5 +104,5 @@ Here are the posts that I’ve written so far for this series: * {{< draftlink "Lattices of Finite Height" "03_spa_agda_fixed_height" >}} * {{< draftlink "The Fixed-Point Algorithm" "04_spa_agda_fixedpoint" >}} * {{< draftlink "Our Programming Language" "05_spa_agda_semantics" >}} -* {{< draftlink "Control Flow Graphs" "06_spa_agda_cfg" >}}. -* {{< draftlink "Connecting Semantics and Control Flow Graphs" "07_spa_agda_semantics_and_cfg" >}}. +* {{< draftlink "Control Flow Graphs" "06_spa_agda_cfg" >}} +* {{< draftlink "Connecting Semantics and Control Flow Graphs" "07_spa_agda_semantics_and_cfg" >}} diff --git a/content/blog/05_spa_agda_semantics/index.md b/content/blog/05_spa_agda_semantics/index.md index cf0fdfc..b08ee5e 100644 --- a/content/blog/05_spa_agda_semantics/index.md +++ b/content/blog/05_spa_agda_semantics/index.md @@ -171,6 +171,7 @@ will be guaranteed to always execute without any decisions or jumps. The reason for this will become clearer in subsequent posts; I will foreshadow a bit by saying that consecutive simple statements can be placed into a single [basic block](https://en.wikipedia.org/wiki/Basic_block). +{#introduce-simple-statements} The following is a group of three simple statements: diff --git a/content/blog/06_spa_agda_cfg/if-cfg.dot b/content/blog/06_spa_agda_cfg/if-cfg.dot new file mode 100644 index 0000000..5a45973 --- /dev/null +++ b/content/blog/06_spa_agda_cfg/if-cfg.dot @@ -0,0 +1,15 @@ +digraph G { + graph[dpi=300 fontsize=14 fontname="Courier New"]; + node[shape=rectangle style="filled" fillcolor="#fafafa" penwidth=0.5 color="#aaaaaa"]; + edge[arrowsize=0.3 color="#444444"] + + node_begin [label="x = ...;\lx\l"] + node_then [label="x = 1\l"] + node_else [label="x = 0\l"] + node_end [label="y = x\l"] + + node_begin -> node_then + node_begin -> node_else + node_then -> node_end + node_else -> node_end +} diff --git a/content/blog/06_spa_agda_cfg/if-cfg.png b/content/blog/06_spa_agda_cfg/if-cfg.png new file mode 100644 index 0000000000000000000000000000000000000000..526320879886eeec52391e8a97376212fce10227 GIT binary patch literal 21067 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%0DwyUsK6&!t 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 + +Here, the initialization of `x` with `...`, as well as the `if` condition (just `x`), +are guaranteed to execute one after another, so they occupy a single node. From there, +depending on the condition, the control flow can jump to one of the +branches of the `if` statement: the "then" branch if the condition is true, +and the "else" branch if the condition is false. As a result, there are two +arrows coming out of the initial node. Once either branch is executed, control +always jumps to the code right after the `if` statement (the `y = x`). Thus, +both the `x = 1` and `x = 0` nodes have a single arrow to the `y = x` node. + +As another example, if you had a loop: + +``` +x = ...; +while x { + x = x - 1; +} +y = x; +``` + +The CFG would look like this: + +{{< figure src="while-cfg.png" label="CFG for simple `while` code." class="small" >}} + +Here, condition of the loop (`x`) is not always guaranteed to execute together +with the code that initializes `x`. That's because the condition of the loop +is checked after every iteration, whereas the code before the loop is executed +only once. As a result, `x = ...` and `x` occupy distinct CFG nodes. From there, +the control flow can proceed in two different ways, depending on the value +of `x`. If `x` is truthy, the program will proceed to the loop body (decrementing `x`). +If `x` is falsy, the program will skip the loop body altogether, and go to the +code right after the loop (`y = x`). This is indicated by the two arrows +going out of the `x` node. After executing the body, we return to the condition +of the loop to see if we need to run another iteration. Because of this, the +decrementing node has an arrow back to the loop condition. + +Now, let's be a bit more precise. Control Flow Graphs are defined as follows: + +* __The nodes__ are [_basic blocks_](https://en.wikipedia.org/wiki/Basic_block). + Paraphrasing Wikipedia's definition, a basic block is a piece of code that + has only one entry point and one exit point. + + The one-entry-point rule means that it's not possible to jump into the middle + of the basic block, executing only half of its instructions. The execution of + a basic block always begins at the top. Symmetrically, the one-exit-point + rule means that you can't jump away to other code (even within the same block), + skipping some instructions. The execution of a basic block always ends at + the bottom. + + As a result of these constraints, when running a basic block, you are + guaranteed to execute every instruction in exactly the order they occur in, + and execute each instruction exactly once. +* __The edges__ are jumps between basic blocks. We've already seen how + `if` and `while` statements introduce these jumps. + +Basic blocks can only be made of code that doen't jump (otherwise, +we violate the single-exit-point policy). In the previous post, +we defined exactly this kind of code as [simple statements]({{< relref "05_spa_agda_semantics#introduce-simple-statements" >}}). +So, in our control flow graph, nodes will be sequences of simple statements. +{#list-basic-stmts} + +### Control Flow Graphs in Agda + +#### Basic Definition +At an abstract level, it's easy to say "it's just a graph where X is Y" about +anything. It's much harder to give a precise definition of such a graph, +particularly if you want to rule out invalid graphs (e.g., ones with edges +pointing nowhere). In Agda, I chose the represent a two lists: one of nodes, +and one of edges. Each node is simply a list of `BasicStmt`s, as +I described in a preceding paragraph. An edge is simply a pair of numbers, +each number encoding the index of the node connected by the edge. + +Here's where it gets a little complicated. I don't want to use plain natural +numbers for indices, because that means you can easily introduce "broken" edge. +For example, what if you have 4 nodes, and you have an edge `(5, 5)`? Therefore, +I picked the finite natural numbers represented by [`Fin`](https://agda.github.io/agda-stdlib/v2.0/Data.Fin.Base.html#1154). + +```Agda +data Fin : ℕ → Set where + zero : Fin (suc n) + suc : (i : Fin n) → Fin (suc n) +``` + +Specifically, `Fin n` is the type of natural numbers less than `n`. Following +this definition, `Fin 3` represents the numbers `0`, `1` and `2`. These are +represented using the same constructors as `Nat`: `zero` and `suc`. The type +of `zero` is `Fin (suc n)` for any `n`; this makes sense because zero is less +than any number plus one. For `suc,` the bound `n` of the input `i` is incremented +by one, leading to another `suc n` in the final type. This makes sense because if +`i < n`, then `i + 1 < n + 1`. I've previously explained this data type +[in another post on this site]({{< relref "01_aoc_coq#aside-vectors-and-finite-mathbbn" >}}). + +Here's my definition of `Graph`s written using `Fin`: + +{{< codelines "Agda" "agda-spa/Language/Graphs.agda" 24 39 >}} + +I explicitly used a `size` field, which determines how many nodes are in the +graph, and serves both as the upper bound the edge indices as well as the +size `nodes` field. From there, an index `Index` into the node list is +{{< sidenote "right" "size-note" "just a natural number less than `size`," >}} +Ther are size natural numbers less than size:
+0, 1, ..., size - 1. +{{< /sidenote >}} +and an edge is just a pair of indices. The graph then contains a vector +(exact-length list) `nodes` of all the basic blocks, and then a list of +edges `edges`. + +There are two fields here that I have not yet said anything about: `inputs` +and `outputs`. When we have a complete CFG for our programs, these fields are +totally unnecessary. However, as we are _building_ the CFG, these will come +in handy, by telling us how to stitch together smaller sub-graphs that we've +already built. Let's talk about that next. + +#### Combining Graphs +Suppose you're building a CFG for a program in the following form: + +``` +code1; +code2; +``` + +Where `code1` and `code2` are arbitrary pieces of code, which could include +statements, loops, and pretty much anything else. Besides the fact that they +occur one after another, these pieces of code are unrelated, and we can +build CFGs for each one them independently. However, the fact that `code1` and +`code2` are in sequence means that the full control flow graph for the above +program should have edges going from the nodes in `code1` to the nodes in `code2`. +Of course, not _every_ node in `code1` should have such edges: that would +mean that after executing any "basic" sequence of instructions, you could suddenly +decide to skip the rest of `code1` and move on to executing `code2`. + +Thus, we need to be more precise about what edges we need to insert; we want +to insert edges between the "final" nodes in `code1` (where control ends up +after `code1` is finished executing) and the "initial" nodes in `code2` (where +control would begin once we started executing `code2`). Those are the `outputs` +and `inputs`, respectively. When stitching together sequenced control graphs, +we will connect each of the outputs of one to each of the inputs of the other. + +This is defined by the operation `_↦_`: + +{{< codelines "Agda" "agda-spa/Language/Graphs.agda" 72 83 >}} diff --git a/content/blog/06_spa_agda_cfg/while-cfg.dot b/content/blog/06_spa_agda_cfg/while-cfg.dot new file mode 100644 index 0000000..ef37a6c --- /dev/null +++ b/content/blog/06_spa_agda_cfg/while-cfg.dot @@ -0,0 +1,15 @@ +digraph G { + graph[dpi=300 fontsize=14 fontname="Courier New"]; + node[shape=rectangle style="filled" fillcolor="#fafafa" penwidth=0.5 color="#aaaaaa"]; + edge[arrowsize=0.3 color="#444444"] + + node_begin [label="x = ...;\l"] + node_cond [label="x\l"] + node_body [label="x = x - 1\l"] + node_end [label="y = x\l"] + + node_begin -> node_cond + node_cond -> node_body + node_cond -> node_end + node_body -> node_cond +} diff --git a/content/blog/06_spa_agda_cfg/while-cfg.png b/content/blog/06_spa_agda_cfg/while-cfg.png new file mode 100644 index 0000000000000000000000000000000000000000..278ce6022d5fd5b827d2cbf18c2098c78a72fd33 GIT binary patch literal 13927 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