github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/src/cmd/compile/internal/ssa/fuse_test.go (about)

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