# 9.5.3 构建数据流有向图

在[总体逻辑](/9.-golang-bian-yi-qi-tao-yi-fen-xi/9.5.1-zong-ti-luo-ji.md)中我们提到构建数据流有向图总共分为三步，但要做的事情实际上只有两类：创建顶点、创建边。

### 创建顶点

对于函数中的每个局部变量，都需要为其创建一个顶点，该逻辑由函数 `initFunc()` 完成：

```go
func (b *batch) initFunc(fn *ir.Func) {
    e := b.with(fn)
    if fn.Esc() != escFuncUnknown {
        base.Fatalf("unexpected node: %v", fn)
    }
    fn.SetEsc(escFuncPlanned)

    // Allocate locations for local variables.
    for _, n := range fn.Dcl {
        if n.Op() == ir.ONAME {
            e.newLoc(n, false)
        }
    }

    // Initialize resultIndex for result parameters.
    for i, f := range fn.Type().Results().FieldSlice() {
        e.oldLoc(f.Nname.(*ir.Name)).resultIndex = 1 + i
    }
}
```

创建顶点的逻辑由第一个 for 循环完成，其遍历函数所有的局部变量，为其创建一个 location 对象，并将其添加到 `b.allLocs` 属性中，该逻辑由 `e.newLoc()` 完成，此处不再贴出代码。第二个 for 循环用来设置返回值变量的索引值，此处不用太关注。

注意此处创建的顶点仅是函数内的命名局部变量，对于通过函数 `new` 与 `make` 创建的顶点，以及各种字面量初始化创建的顶点，需要在构造有向图边的时候才能创建。

### 创建有向边

构造有向边的逻辑更加复杂，因为只有对函数的所有语句进行分析之后，才能够构建出完整的赋值关系，从而构建出完整的数据流有向图。

分析赋值关系的逻辑入口是 `batch.walkFunc(ir.Func)`, 该方法对目标函数的所有语句递归遍历并进行分析，如果语句中存在赋值关系，则为其创建有向边。该逻辑涉及到的代码很多，但主体框架可以由如下几个函数体现：

* escape.stmt(ir.Node) 对单个语句进行分析的方法，该函数通过一个巨大的 `switch...case` 对各种类型的语句进行处理。例如对于赋值语句，该函数最终会为赋值语句两边的顶点建立一条有向边。
* escape.expr(h hole, n ir.Node) 该函数模拟对表达式 `n` 进行求值，并将求值策略保存在参数 `h` 中，可以将该方法理解为为节点 `n` 所表示的表达式构建对应的 `hole` 实例。
* batch.flow(h hole, src location) 建立从 `src` 到 `h.dst` 两个顶点的有向边。

&#x20;读者可以通过[Unit Test](/9.-golang-bian-yi-qi-tao-yi-fen-xi/9.7-unit-test.md)部分介绍的方式对总体构建逻辑进行调试。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gocompiler.shizhz.me/9.-golang-bian-yi-qi-tao-yi-fen-xi/9.5.3-gou-jian-shu-ju-liu-you-xiang-tu.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
