github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/ssa/branchelim_test.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ssa
     6  
     7  import (
     8  	"cmd/compile/internal/types"
     9  	"testing"
    10  )
    11  
    12  // Test that a trivial 'if' is eliminated
    13  func TestBranchElimIf(t *testing.T) {
    14  	c := testConfig(t)
    15  	c.config.arch = "arm64" // FIXME
    16  	boolType := types.New(types.TBOOL)
    17  	intType := types.New(types.TINT32)
    18  	fun := c.Fun("entry",
    19  		Bloc("entry",
    20  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    21  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
    22  			Valu("const1", OpConst32, intType, 1, nil),
    23  			Valu("const2", OpConst32, intType, 2, nil),
    24  			Valu("addr", OpAddr, boolType.PtrTo(), 0, nil, "sb"),
    25  			Valu("cond", OpLoad, boolType, 0, nil, "addr", "start"),
    26  			If("cond", "b2", "b3")),
    27  		Bloc("b2",
    28  			Goto("b3")),
    29  		Bloc("b3",
    30  			Valu("phi", OpPhi, intType, 0, nil, "const1", "const2"),
    31  			Valu("retstore", OpStore, types.TypeMem, 0, nil, "phi", "sb", "start"),
    32  			Exit("retstore")))
    33  
    34  	CheckFunc(fun.f)
    35  	branchelim(fun.f)
    36  	CheckFunc(fun.f)
    37  	Deadcode(fun.f)
    38  	CheckFunc(fun.f)
    39  
    40  	if len(fun.f.Blocks) != 1 {
    41  		t.Errorf("expected 1 block after branchelim and deadcode; found %d", len(fun.f.Blocks))
    42  	}
    43  	if fun.values["phi"].Op != OpCondSelect {
    44  		t.Errorf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
    45  	}
    46  	if fun.values["phi"].Args[2] != fun.values["cond"] {
    47  		t.Errorf("expected CondSelect condition to be %s; found %s", fun.values["cond"], fun.values["phi"].Args[2])
    48  	}
    49  	if fun.blocks["entry"].Kind != BlockExit {
    50  		t.Errorf("expected entry to be BlockExit; found kind %s", fun.blocks["entry"].Kind.String())
    51  	}
    52  }
    53  
    54  // Test that a trivial if/else is eliminated
    55  func TestBranchElimIfElse(t *testing.T) {
    56  	c := testConfig(t)
    57  	c.config.arch = "arm64" // FIXME
    58  	boolType := types.New(types.TBOOL)
    59  	intType := types.New(types.TINT32)
    60  	fun := c.Fun("entry",
    61  		Bloc("entry",
    62  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    63  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
    64  			Valu("const1", OpConst32, intType, 1, nil),
    65  			Valu("const2", OpConst32, intType, 2, nil),
    66  			Valu("addr", OpAddr, boolType.PtrTo(), 0, nil, "sb"),
    67  			Valu("cond", OpLoad, boolType, 0, nil, "addr", "start"),
    68  			If("cond", "b2", "b3")),
    69  		Bloc("b2",
    70  			Goto("b4")),
    71  		Bloc("b3",
    72  			Goto("b4")),
    73  		Bloc("b4",
    74  			Valu("phi", OpPhi, intType, 0, nil, "const1", "const2"),
    75  			Valu("retstore", OpStore, types.TypeMem, 0, nil, "phi", "sb", "start"),
    76  			Exit("retstore")))
    77  
    78  	CheckFunc(fun.f)
    79  	branchelim(fun.f)
    80  	CheckFunc(fun.f)
    81  	Deadcode(fun.f)
    82  	CheckFunc(fun.f)
    83  
    84  	if len(fun.f.Blocks) != 1 {
    85  		t.Errorf("expected 1 block after branchelim; found %d", len(fun.f.Blocks))
    86  	}
    87  	if fun.values["phi"].Op != OpCondSelect {
    88  		t.Errorf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
    89  	}
    90  	if fun.values["phi"].Args[2] != fun.values["cond"] {
    91  		t.Errorf("expected CondSelect condition to be %s; found %s", fun.values["cond"], fun.values["phi"].Args[2])
    92  	}
    93  	if fun.blocks["entry"].Kind != BlockExit {
    94  		t.Errorf("expected entry to be BlockExit; found kind %s", fun.blocks["entry"].Kind.String())
    95  	}
    96  }
    97  
    98  // Test that an if/else CFG that loops back
    99  // into itself does *not* get eliminated.
   100  func TestNoBranchElimLoop(t *testing.T) {
   101  	c := testConfig(t)
   102  	c.config.arch = "arm64" // FIXME
   103  	boolType := types.New(types.TBOOL)
   104  	intType := types.New(types.TINT32)
   105  
   106  	// The control flow here is totally bogus,
   107  	// but a dead cycle seems like the only plausible
   108  	// way to arrive at a diamond CFG that is also a loop.
   109  	fun := c.Fun("entry",
   110  		Bloc("entry",
   111  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
   112  			Valu("sb", OpSB, types.TypeInvalid, 0, nil),
   113  			Valu("const2", OpConst32, intType, 2, nil),
   114  			Valu("const3", OpConst32, intType, 3, nil),
   115  			Goto("b5")),
   116  		Bloc("b2",
   117  			Valu("addr", OpAddr, boolType.PtrTo(), 0, nil, "sb"),
   118  			Valu("cond", OpLoad, boolType, 0, nil, "addr", "start"),
   119  			Valu("phi", OpPhi, intType, 0, nil, "const2", "const3"),
   120  			If("cond", "b3", "b4")),
   121  		Bloc("b3",
   122  			Goto("b2")),
   123  		Bloc("b4",
   124  			Goto("b2")),
   125  		Bloc("b5",
   126  			Exit("start")))
   127  
   128  	CheckFunc(fun.f)
   129  	branchelim(fun.f)
   130  	CheckFunc(fun.f)
   131  
   132  	if len(fun.f.Blocks) != 5 {
   133  		t.Errorf("expected 5 block after branchelim; found %d", len(fun.f.Blocks))
   134  	}
   135  	if fun.values["phi"].Op != OpPhi {
   136  		t.Errorf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
   137  	}
   138  }