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

     1  // Copyright 2015 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 "testing"
     8  
     9  func TestSchedule(t *testing.T) {
    10  	c := testConfig(t)
    11  	cases := []fun{
    12  		c.Fun("entry",
    13  			Bloc("entry",
    14  				Valu("mem0", OpInitMem, TypeMem, 0, nil),
    15  				Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil),
    16  				Valu("v", OpConst64, TypeInt64, 12, nil),
    17  				Valu("mem1", OpStore, TypeMem, 0, TypeInt64, "ptr", "v", "mem0"),
    18  				Valu("mem2", OpStore, TypeMem, 0, TypeInt64, "ptr", "v", "mem1"),
    19  				Valu("mem3", OpStore, TypeMem, 0, TypeInt64, "ptr", "sum", "mem2"),
    20  				Valu("l1", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"),
    21  				Valu("l2", OpLoad, TypeInt64, 0, nil, "ptr", "mem2"),
    22  				Valu("sum", OpAdd64, TypeInt64, 0, nil, "l1", "l2"),
    23  				Goto("exit")),
    24  			Bloc("exit",
    25  				Exit("mem3"))),
    26  	}
    27  	for _, c := range cases {
    28  		schedule(c.f)
    29  		if !isSingleLiveMem(c.f) {
    30  			t.Error("single-live-mem restriction not enforced by schedule for func:")
    31  			printFunc(c.f)
    32  		}
    33  	}
    34  }
    35  
    36  func isSingleLiveMem(f *Func) bool {
    37  	for _, b := range f.Blocks {
    38  		var liveMem *Value
    39  		for _, v := range b.Values {
    40  			for _, w := range v.Args {
    41  				if w.Type.IsMemory() {
    42  					if liveMem == nil {
    43  						liveMem = w
    44  						continue
    45  					}
    46  					if w != liveMem {
    47  						return false
    48  					}
    49  				}
    50  			}
    51  			if v.Type.IsMemory() {
    52  				liveMem = v
    53  			}
    54  		}
    55  	}
    56  	return true
    57  }
    58  
    59  func TestStoreOrder(t *testing.T) {
    60  	// In the function below, v2 depends on v3 and v4, v4 depends on v3, and v3 depends on store v5.
    61  	// storeOrder did not handle this case correctly.
    62  	c := testConfig(t)
    63  	fun := c.Fun("entry",
    64  		Bloc("entry",
    65  			Valu("mem0", OpInitMem, TypeMem, 0, nil),
    66  			Valu("a", OpAdd64, TypeInt64, 0, nil, "b", "c"),                  // v2
    67  			Valu("b", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"),              // v3
    68  			Valu("c", OpNeg64, TypeInt64, 0, nil, "b"),                       // v4
    69  			Valu("mem1", OpStore, TypeMem, 0, TypeInt64, "ptr", "v", "mem0"), // v5
    70  			Valu("mem2", OpStore, TypeMem, 0, TypeInt64, "ptr", "a", "mem1"),
    71  			Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil),
    72  			Valu("v", OpConst64, TypeInt64, 12, nil),
    73  			Goto("exit")),
    74  		Bloc("exit",
    75  			Exit("mem2")))
    76  
    77  	CheckFunc(fun.f)
    78  	order := storeOrder(fun.f.Blocks[0].Values, fun.f.newSparseSet(fun.f.NumValues()), make([]int32, fun.f.NumValues()))
    79  
    80  	// check that v2, v3, v4 is sorted after v5
    81  	var ai, bi, ci, si int
    82  	for i, v := range order {
    83  		switch v.ID {
    84  		case 2:
    85  			ai = i
    86  		case 3:
    87  			bi = i
    88  		case 4:
    89  			ci = i
    90  		case 5:
    91  			si = i
    92  		}
    93  	}
    94  	if ai < si || bi < si || ci < si {
    95  		t.Logf("Func: %s", fun.f)
    96  		t.Errorf("store order is wrong: got %v, want v2 v3 v4 after v5", order)
    97  	}
    98  }