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