Home | History | Annotate | Download | only in ssa
      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, types.TypeInvalid, 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, types.TypeInvalid, 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, types.TypeInvalid, 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, types.TypeInvalid, 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