github.com/stingnevermore/go@v0.0.0-20180120041312-3810f5bfed72/src/cmd/compile/internal/ssa/fuse_test.go (about)

     1  package ssa
     2  
     3  import (
     4  	"cmd/compile/internal/types"
     5  	"fmt"
     6  	"strconv"
     7  	"testing"
     8  )
     9  
    10  func TestFuseEliminatesOneBranch(t *testing.T) {
    11  	c := testConfig(t)
    12  	ptrType := c.config.Types.BytePtr
    13  	fun := c.Fun("entry",
    14  		Bloc("entry",
    15  			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
    16  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
    17  			Goto("checkPtr")),
    18  		Bloc("checkPtr",
    19  			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
    20  			Valu("nilptr", OpConstNil, ptrType, 0, nil),
    21  			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
    22  			If("bool1", "then", "exit")),
    23  		Bloc("then",
    24  			Goto("exit")),
    25  		Bloc("exit",
    26  			Exit("mem")))
    27  
    28  	CheckFunc(fun.f)
    29  	fuse(fun.f)
    30  
    31  	for _, b := range fun.f.Blocks {
    32  		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
    33  			t.Errorf("then was not eliminated, but should have")
    34  		}
    35  	}
    36  }
    37  
    38  func TestFuseEliminatesBothBranches(t *testing.T) {
    39  	c := testConfig(t)
    40  	ptrType := c.config.Types.BytePtr
    41  	fun := c.Fun("entry",
    42  		Bloc("entry",
    43  			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
    44  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
    45  			Goto("checkPtr")),
    46  		Bloc("checkPtr",
    47  			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
    48  			Valu("nilptr", OpConstNil, ptrType, 0, nil),
    49  			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
    50  			If("bool1", "then", "else")),
    51  		Bloc("then",
    52  			Goto("exit")),
    53  		Bloc("else",
    54  			Goto("exit")),
    55  		Bloc("exit",
    56  			Exit("mem")))
    57  
    58  	CheckFunc(fun.f)
    59  	fuse(fun.f)
    60  
    61  	for _, b := range fun.f.Blocks {
    62  		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
    63  			t.Errorf("then was not eliminated, but should have")
    64  		}
    65  		if b == fun.blocks["else"] && b.Kind != BlockInvalid {
    66  			t.Errorf("then was not eliminated, but should have")
    67  		}
    68  	}
    69  }
    70  
    71  func TestFuseHandlesPhis(t *testing.T) {
    72  	c := testConfig(t)
    73  	ptrType := c.config.Types.BytePtr
    74  	fun := c.Fun("entry",
    75  		Bloc("entry",
    76  			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
    77  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
    78  			Goto("checkPtr")),
    79  		Bloc("checkPtr",
    80  			Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"),
    81  			Valu("nilptr", OpConstNil, ptrType, 0, nil),
    82  			Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"),
    83  			If("bool1", "then", "else")),
    84  		Bloc("then",
    85  			Goto("exit")),
    86  		Bloc("else",
    87  			Goto("exit")),
    88  		Bloc("exit",
    89  			Valu("phi", OpPhi, ptrType, 0, nil, "ptr1", "ptr1"),
    90  			Exit("mem")))
    91  
    92  	CheckFunc(fun.f)
    93  	fuse(fun.f)
    94  
    95  	for _, b := range fun.f.Blocks {
    96  		if b == fun.blocks["then"] && b.Kind != BlockInvalid {
    97  			t.Errorf("then was not eliminated, but should have")
    98  		}
    99  		if b == fun.blocks["else"] && b.Kind != BlockInvalid {
   100  			t.Errorf("then was not eliminated, but should have")
   101  		}
   102  	}
   103  }
   104  
   105  func TestFuseEliminatesEmptyBlocks(t *testing.T) {
   106  	c := testConfig(t)
   107  	fun := c.Fun("entry",
   108  		Bloc("entry",
   109  			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
   110  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
   111  			Goto("z0")),
   112  		Bloc("z1",
   113  			Goto("z2")),
   114  		Bloc("z3",
   115  			Goto("exit")),
   116  		Bloc("z2",
   117  			Goto("z3")),
   118  		Bloc("z0",
   119  			Goto("z1")),
   120  		Bloc("exit",
   121  			Exit("mem"),
   122  		))
   123  
   124  	CheckFunc(fun.f)
   125  	fuse(fun.f)
   126  
   127  	for k, b := range fun.blocks {
   128  		if k[:1] == "z" && b.Kind != BlockInvalid {
   129  			t.Errorf("%s was not eliminated, but should have", k)
   130  		}
   131  	}
   132  }
   133  
   134  func BenchmarkFuse(b *testing.B) {
   135  	for _, n := range [...]int{1, 10, 100, 1000, 10000} {
   136  		b.Run(strconv.Itoa(n), func(b *testing.B) {
   137  			c := testConfig(b)
   138  
   139  			blocks := make([]bloc, 0, 2*n+3)
   140  			blocks = append(blocks,
   141  				Bloc("entry",
   142  					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
   143  					Valu("cond", OpArg, c.config.Types.Bool, 0, nil),
   144  					Valu("x", OpArg, c.config.Types.Int64, 0, nil),
   145  					Goto("exit")))
   146  
   147  			phiArgs := make([]string, 0, 2*n)
   148  			for i := 0; i < n; i++ {
   149  				cname := fmt.Sprintf("c%d", i)
   150  				blocks = append(blocks,
   151  					Bloc(fmt.Sprintf("b%d", i), If("cond", cname, "merge")),
   152  					Bloc(cname, Goto("merge")))
   153  				phiArgs = append(phiArgs, "x", "x")
   154  			}
   155  			blocks = append(blocks,
   156  				Bloc("merge",
   157  					Valu("phi", OpPhi, types.TypeMem, 0, nil, phiArgs...),
   158  					Goto("exit")),
   159  				Bloc("exit",
   160  					Exit("mem")))
   161  
   162  			b.ResetTimer()
   163  			for i := 0; i < b.N; i++ {
   164  				fun := c.Fun("entry", blocks...)
   165  				fuse(fun.f)
   166  			}
   167  		})
   168  	}
   169  }