Source file src/cmd/compile/internal/ssa/deadstore_test.go

     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 (
     8  	"cmd/compile/internal/types"
     9  	"cmd/internal/src"
    10  	"testing"
    11  )
    12  
    13  func TestDeadStore(t *testing.T) {
    14  	c := testConfig(t)
    15  	ptrType := c.config.Types.BytePtr
    16  	t.Logf("PTRTYPE %v", ptrType)
    17  	fun := c.Fun("entry",
    18  		Bloc("entry",
    19  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    20  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    21  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    22  			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
    23  			Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
    24  			Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
    25  			Valu("zero1", OpZero, types.TypeMem, 1, c.config.Types.Bool, "addr3", "start"),
    26  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "zero1"),
    27  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
    28  			Valu("store3", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store2"),
    29  			Valu("store4", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr3", "v", "store3"),
    30  			Goto("exit")),
    31  		Bloc("exit",
    32  			Exit("store3")))
    33  
    34  	CheckFunc(fun.f)
    35  	dse(fun.f)
    36  	CheckFunc(fun.f)
    37  
    38  	v1 := fun.values["store1"]
    39  	if v1.Op != OpCopy {
    40  		t.Errorf("dead store not removed")
    41  	}
    42  
    43  	v2 := fun.values["zero1"]
    44  	if v2.Op != OpCopy {
    45  		t.Errorf("dead store (zero) not removed")
    46  	}
    47  }
    48  
    49  func TestDeadStorePhi(t *testing.T) {
    50  	// make sure we don't get into an infinite loop with phi values.
    51  	c := testConfig(t)
    52  	ptrType := c.config.Types.BytePtr
    53  	fun := c.Fun("entry",
    54  		Bloc("entry",
    55  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    56  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    57  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    58  			Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
    59  			Goto("loop")),
    60  		Bloc("loop",
    61  			Valu("phi", OpPhi, types.TypeMem, 0, nil, "start", "store"),
    62  			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr", "v", "phi"),
    63  			If("v", "loop", "exit")),
    64  		Bloc("exit",
    65  			Exit("store")))
    66  
    67  	CheckFunc(fun.f)
    68  	dse(fun.f)
    69  	CheckFunc(fun.f)
    70  }
    71  
    72  func TestDeadStoreTypes(t *testing.T) {
    73  	// Make sure a narrow store can't shadow a wider one. We test an even
    74  	// stronger restriction, that one store can't shadow another unless the
    75  	// types of the address fields are identical (where identicalness is
    76  	// decided by the CSE pass).
    77  	c := testConfig(t)
    78  	t1 := c.config.Types.UInt64.PtrTo()
    79  	t2 := c.config.Types.UInt32.PtrTo()
    80  	fun := c.Fun("entry",
    81  		Bloc("entry",
    82  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    83  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    84  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    85  			Valu("addr1", OpAddr, t1, 0, nil, "sb"),
    86  			Valu("addr2", OpAddr, t2, 0, nil, "sb"),
    87  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "start"),
    88  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
    89  			Goto("exit")),
    90  		Bloc("exit",
    91  			Exit("store2")))
    92  
    93  	CheckFunc(fun.f)
    94  	cse(fun.f)
    95  	dse(fun.f)
    96  	CheckFunc(fun.f)
    97  
    98  	v := fun.values["store1"]
    99  	if v.Op == OpCopy {
   100  		t.Errorf("store %s incorrectly removed", v)
   101  	}
   102  }
   103  
   104  func TestDeadStoreUnsafe(t *testing.T) {
   105  	// Make sure a narrow store can't shadow a wider one. The test above
   106  	// covers the case of two different types, but unsafe pointer casting
   107  	// can get to a point where the size is changed but type unchanged.
   108  	c := testConfig(t)
   109  	ptrType := c.config.Types.UInt64.PtrTo()
   110  	fun := c.Fun("entry",
   111  		Bloc("entry",
   112  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
   113  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
   114  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
   115  			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
   116  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "addr1", "v", "start"), // store 8 bytes
   117  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store1"), // store 1 byte
   118  			Goto("exit")),
   119  		Bloc("exit",
   120  			Exit("store2")))
   121  
   122  	CheckFunc(fun.f)
   123  	cse(fun.f)
   124  	dse(fun.f)
   125  	CheckFunc(fun.f)
   126  
   127  	v := fun.values["store1"]
   128  	if v.Op == OpCopy {
   129  		t.Errorf("store %s incorrectly removed", v)
   130  	}
   131  }
   132  
   133  func TestDeadStoreSmallStructInit(t *testing.T) {
   134  	c := testConfig(t)
   135  	ptrType := c.config.Types.BytePtr
   136  	typ := types.NewStruct([]*types.Field{
   137  		types.NewField(src.NoXPos, &types.Sym{Name: "A"}, c.config.Types.Int),
   138  		types.NewField(src.NoXPos, &types.Sym{Name: "B"}, c.config.Types.Int),
   139  	})
   140  	name := c.Temp(typ)
   141  	fun := c.Fun("entry",
   142  		Bloc("entry",
   143  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
   144  			Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil),
   145  			Valu("zero", OpConst64, c.config.Types.Int, 0, nil),
   146  			Valu("v6", OpLocalAddr, ptrType, 0, name, "sp", "start"),
   147  			Valu("v3", OpOffPtr, ptrType, 8, nil, "v6"),
   148  			Valu("v22", OpOffPtr, ptrType, 0, nil, "v6"),
   149  			Valu("zerostore1", OpStore, types.TypeMem, 0, c.config.Types.Int, "v22", "zero", "start"),
   150  			Valu("zerostore2", OpStore, types.TypeMem, 0, c.config.Types.Int, "v3", "zero", "zerostore1"),
   151  			Valu("v8", OpLocalAddr, ptrType, 0, name, "sp", "zerostore2"),
   152  			Valu("v23", OpOffPtr, ptrType, 8, nil, "v8"),
   153  			Valu("v25", OpOffPtr, ptrType, 0, nil, "v8"),
   154  			Valu("zerostore3", OpStore, types.TypeMem, 0, c.config.Types.Int, "v25", "zero", "zerostore2"),
   155  			Valu("zerostore4", OpStore, types.TypeMem, 0, c.config.Types.Int, "v23", "zero", "zerostore3"),
   156  			Goto("exit")),
   157  		Bloc("exit",
   158  			Exit("zerostore4")))
   159  
   160  	fun.f.Name = "smallstructinit"
   161  	CheckFunc(fun.f)
   162  	cse(fun.f)
   163  	dse(fun.f)
   164  	CheckFunc(fun.f)
   165  
   166  	v1 := fun.values["zerostore1"]
   167  	if v1.Op != OpCopy {
   168  		t.Errorf("dead store not removed")
   169  	}
   170  	v2 := fun.values["zerostore2"]
   171  	if v2.Op != OpCopy {
   172  		t.Errorf("dead store not removed")
   173  	}
   174  }
   175  

View as plain text