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  	"testing"
    10  )
    11  
    12  func TestDeadStore(t *testing.T) {
    13  	c := testConfig(t)
    14  	ptrType := c.config.Types.BytePtr
    15  	t.Logf("PTRTYPE %v", ptrType)
    16  	fun := c.Fun("entry",
    17  		Bloc("entry",
    18  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    19  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    20  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    21  			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
    22  			Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
    23  			Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
    24  			Valu("zero1", OpZero, types.TypeMem, 1, c.config.Types.Bool, "addr3", "start"),
    25  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "zero1"),
    26  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
    27  			Valu("store3", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store2"),
    28  			Valu("store4", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr3", "v", "store3"),
    29  			Goto("exit")),
    30  		Bloc("exit",
    31  			Exit("store3")))
    32  
    33  	CheckFunc(fun.f)
    34  	dse(fun.f)
    35  	CheckFunc(fun.f)
    36  
    37  	v1 := fun.values["store1"]
    38  	if v1.Op != OpCopy {
    39  		t.Errorf("dead store not removed")
    40  	}
    41  
    42  	v2 := fun.values["zero1"]
    43  	if v2.Op != OpCopy {
    44  		t.Errorf("dead store (zero) not removed")
    45  	}
    46  }
    47  func TestDeadStorePhi(t *testing.T) {
    48  	// make sure we don't get into an infinite loop with phi values.
    49  	c := testConfig(t)
    50  	ptrType := c.config.Types.BytePtr
    51  	fun := c.Fun("entry",
    52  		Bloc("entry",
    53  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    54  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    55  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    56  			Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
    57  			Goto("loop")),
    58  		Bloc("loop",
    59  			Valu("phi", OpPhi, types.TypeMem, 0, nil, "start", "store"),
    60  			Valu("store", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr", "v", "phi"),
    61  			If("v", "loop", "exit")),
    62  		Bloc("exit",
    63  			Exit("store")))
    64  
    65  	CheckFunc(fun.f)
    66  	dse(fun.f)
    67  	CheckFunc(fun.f)
    68  }
    69  
    70  func TestDeadStoreTypes(t *testing.T) {
    71  	// Make sure a narrow store can't shadow a wider one. We test an even
    72  	// stronger restriction, that one store can't shadow another unless the
    73  	// types of the address fields are identical (where identicalness is
    74  	// decided by the CSE pass).
    75  	c := testConfig(t)
    76  	t1 := c.config.Types.UInt64.PtrTo()
    77  	t2 := c.config.Types.UInt32.PtrTo()
    78  	fun := c.Fun("entry",
    79  		Bloc("entry",
    80  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
    81  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
    82  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
    83  			Valu("addr1", OpAddr, t1, 0, nil, "sb"),
    84  			Valu("addr2", OpAddr, t2, 0, nil, "sb"),
    85  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "start"),
    86  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr2", "v", "store1"),
    87  			Goto("exit")),
    88  		Bloc("exit",
    89  			Exit("store2")))
    90  
    91  	CheckFunc(fun.f)
    92  	cse(fun.f)
    93  	dse(fun.f)
    94  	CheckFunc(fun.f)
    95  
    96  	v := fun.values["store1"]
    97  	if v.Op == OpCopy {
    98  		t.Errorf("store %s incorrectly removed", v)
    99  	}
   100  }
   101  
   102  func TestDeadStoreUnsafe(t *testing.T) {
   103  	// Make sure a narrow store can't shadow a wider one. The test above
   104  	// covers the case of two different types, but unsafe pointer casting
   105  	// can get to a point where the size is changed but type unchanged.
   106  	c := testConfig(t)
   107  	ptrType := c.config.Types.UInt64.PtrTo()
   108  	fun := c.Fun("entry",
   109  		Bloc("entry",
   110  			Valu("start", OpInitMem, types.TypeMem, 0, nil),
   111  			Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
   112  			Valu("v", OpConstBool, c.config.Types.Bool, 1, nil),
   113  			Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
   114  			Valu("store1", OpStore, types.TypeMem, 0, c.config.Types.Int64, "addr1", "v", "start"), // store 8 bytes
   115  			Valu("store2", OpStore, types.TypeMem, 0, c.config.Types.Bool, "addr1", "v", "store1"), // store 1 byte
   116  			Goto("exit")),
   117  		Bloc("exit",
   118  			Exit("store2")))
   119  
   120  	CheckFunc(fun.f)
   121  	cse(fun.f)
   122  	dse(fun.f)
   123  	CheckFunc(fun.f)
   124  
   125  	v := fun.values["store1"]
   126  	if v.Op == OpCopy {
   127  		t.Errorf("store %s incorrectly removed", v)
   128  	}
   129  }
   130  

View as plain text