# 5.5 编译日志

如果查看 `irgen.generate()` 的完整代码，可以发现如下代码片段：

```go
if base.Flag.W > 1 {
    for _, n := range g.target.Decls {
        s := fmt.Sprintf("\nafter noder2 %v", n)
        ir.Dump(s, n)
    }
}
```

可见 IR Tree 并没有完全隐藏在编译器内部，而是可以通过编译参数 `-W` 来查看，并且编译器不仅会 dump 出 IR Tree 的结构，还会 dump 出泛型函数实例化时所做的改变。我们通过一个例子来查看一下。

将下列代码保存为 main.go:

```go
package main

import "fmt"

func genericFun[T any](i, j T)  {
    fmt.Printf("i: %v, j: %v\n",i, j)
}

func main() {
    genericFun(5,6)
    genericFun[float32](10.5, 11.8)
}
```

通过命令 `go tool compile -G=2 -W=2 main.go` 进行编译即可看到如下结果：

> ```
> after noder2 genericFun [0xc0001642c0]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal FUNC-func[T₁](T₁, T₁) # main.go:5
> .   DCLFUNC-Dcl
> .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack main.T₁ # main.go:5
> .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack main.T₁ # main.go:5
> .   DCLFUNC-body
> .   .   CALLFUNC tc(1) Use:3 STRUCT-(int, error) # main.go:6 STRUCT-(int, error)
> .   .   .   NAME-fmt.Printf tc(1) Class:PFUNC Offset:0 FUNC-func(string, …interface {}) (int, error) # print.go:212
> .   .   CALLFUNC-Args
> .   .   .   LITERAL-“i: %v, j: %v\n” tc(1) string # main.go:6
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack main.T₁ # main.go:5
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack main.T₁ # main.go:5
>
> after noder2 main [0xc000164580]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal FUNC-func() # main.go:9
> .   DCLFUNC-body
> .   .   CALL tc(1) Use:3 # main.go:10
> .   .   .   FUNCINST tc(1) FUNC-func[T₁](T₁, T₁) # main.go:10 FUNC-func[T₁](T₁, T₁)
> .   .   .   .   NAME-main.genericFun tc(1) Class:PFUNC Offset:0 FUNC-func[T₁](T₁, T₁) # main.go:5
> .   .   .   FUNCINST-Targs
> .   .   .   .   TYPE .int Offset:0 type int
> .   .   CALL-Args
> .   .   .   LITERAL-5 tc(1) int # main.go:10
> .   .   .   LITERAL-6 tc(1) int # main.go:10
> .   .   CALL tc(1) Use:3 # main.go:11
> .   .   .   FUNCINST tc(1) FUNC-func[T₁](T₁, T₁) # main.go:11 FUNC-func[T₁](T₁, T₁)
> .   .   .   .   NAME-main.genericFun tc(1) Class:PFUNC Offset:0 FUNC-func[T₁](T₁, T₁) # main.go:5
> .   .   .   FUNCINST-Targs
> .   .   .   .   TYPE .float32 Offset:0 type float32
> .   .   CALL-Args
> .   .   .   LITERAL-10.5 tc(1) float32 # main.go:11
> .   .   .   LITERAL-11.8 tc(1) float32 # main.go:11
>
> stenciled genericFun[int] [0xc0001646e0]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal FUNC-func(int, int) # main.go:5
> .   DCLFUNC-Dcl
> .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack int # main.go:5
> .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack int # main.go:5
> .   DCLFUNC-body
> .   .   CALLFUNC tc(1) Use:3 STRUCT-(int, error) # main.go:6 STRUCT-(int, error)
> .   .   .   NAME-fmt.Printf tc(1) Class:PFUNC Offset:0 FUNC-func(string, …interface {}) (int, error) # print.go:212
> .   .   CALLFUNC-Args
> .   .   .   LITERAL-“i: %v, j: %v\n” tc(1) string # main.go:6
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack int # main.go:5
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack int # main.go:5
>
> stenciled genericFun[float32] [0xc000164840]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal FUNC-func(float32, float32) # main.go:5
> .   DCLFUNC-Dcl
> .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack float32 # main.go:5
> .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack float32 # main.go:5
> .   DCLFUNC-body
> .   .   CALLFUNC tc(1) Use:3 STRUCT-(int, error) # main.go:6 STRUCT-(int, error)
> .   .   .   NAME-fmt.Printf tc(1) Class:PFUNC Offset:0 FUNC-func(string, …interface {}) (int, error) # print.go:212
> .   .   CALLFUNC-Args
> .   .   .   LITERAL-“i: %v, j: %v\n” tc(1) string # main.go:6
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.i tc(1) Class:PPARAM Offset:0 OnStack float32 # main.go:5
> .   .   .   CONVIFACE tc(1) Implicit INTER-interface {} # main.go:6 INTER-interface {}
> .   .   .   .   NAME-main.j tc(1) Class:PPARAM Offset:0 OnStack float32 # main.go:5
>
> modified main [0xc000164580]
> .   DCLFUNC tc(1) Iota:-1 ABI:ABIInternal FUNC-func() # main.go:9
> .   DCLFUNC-body
> .   .   CALLFUNC tc(1) Use:3 # main.go:10
> .   .   .   NAME-main.genericFun[int] tc(1) Class:PFUNC Offset:0 FUNC-func(int, int) # main.go:5
> .   .   CALLFUNC-Args
> .   .   .   LITERAL-5 tc(1) int # main.go:10
> .   .   .   LITERAL-6 tc(1) int # main.go:10
> .   .   CALLFUNC tc(1) Use:3 # main.go:11
> .   .   .   NAME-main.genericFun[float32] tc(1) Class:PFUNC Offset:0 FUNC-func(float32, float32) # main.go:5
> .   .   CALLFUNC-Args
> .   .   .   LITERAL-10.5 tc(1) float32 # main.go:11
> .   .   .   LITERAL-11.8 tc(1) float32 # main.go:11
> ```

前两个以 `after noder2` 开头的结构分别对应两个函数申明，这是 Step 3 完成之后 IR Tree 的总体结构，可以看到其中还包括泛型信息；而随后的信息是泛型函数实例化的 dump 信息，以 `stenciled` 开头的两个函数 `genericFun[int]` 与 `genericFun[float32]` 便是生成的实例化函数，最后 `modified main` 是修改之后的 main 函数，可以发现此时 main 函数内部直接调用的是实例化函数，已经抹掉了有关泛型的所有信息。

编译参数加上 `-G=2` 是为了启用泛型支持以便调用新的类型检查逻辑，并且在创建 IR Tree 完成之后退出编译，否则会 dump 出非常多的信息。可以在 `irgen.go` 的函数 `check2()` 中查看该 flag 的使用方式。
