1// Copyright 2016 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 5package ssa 6 7import ( 8 "cmd/compile/internal/types" 9 "testing" 10) 11 12type tstAux struct { 13 s string 14} 15 16func (*tstAux) CanBeAnSSAAux() {} 17 18// This tests for a bug found when partitioning, but not sorting by the Aux value. 19func TestCSEAuxPartitionBug(t *testing.T) { 20 c := testConfig(t) 21 arg1Aux := &tstAux{"arg1-aux"} 22 arg2Aux := &tstAux{"arg2-aux"} 23 arg3Aux := &tstAux{"arg3-aux"} 24 a := c.Temp(c.config.Types.Int8.PtrTo()) 25 26 // construct lots of values with args that have aux values and place 27 // them in an order that triggers the bug 28 fun := c.Fun("entry", 29 Bloc("entry", 30 Valu("start", OpInitMem, types.TypeMem, 0, nil), 31 Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil), 32 Valu("r7", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg1"), 33 Valu("r1", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"), 34 Valu("arg1", OpArg, c.config.Types.Int64, 0, arg1Aux), 35 Valu("arg2", OpArg, c.config.Types.Int64, 0, arg2Aux), 36 Valu("arg3", OpArg, c.config.Types.Int64, 0, arg3Aux), 37 Valu("r9", OpAdd64, c.config.Types.Int64, 0, nil, "r7", "r8"), 38 Valu("r4", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"), 39 Valu("r8", OpAdd64, c.config.Types.Int64, 0, nil, "arg3", "arg2"), 40 Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"), 41 Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"), 42 Valu("raddrdef", OpVarDef, types.TypeMem, 0, a, "start"), 43 Valu("r6", OpAdd64, c.config.Types.Int64, 0, nil, "r4", "r5"), 44 Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "arg1", "arg2"), 45 Valu("r5", OpAdd64, c.config.Types.Int64, 0, nil, "r2", "r3"), 46 Valu("r10", OpAdd64, c.config.Types.Int64, 0, nil, "r6", "r9"), 47 Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r10", "raddrdef"), 48 Goto("exit")), 49 Bloc("exit", 50 Exit("rstore"))) 51 52 CheckFunc(fun.f) 53 cse(fun.f) 54 deadcode(fun.f) 55 CheckFunc(fun.f) 56 57 s1Cnt := 2 58 // r1 == r2 == r3, needs to remove two of this set 59 s2Cnt := 1 60 // r4 == r5, needs to remove one of these 61 for k, v := range fun.values { 62 if v.Op == OpInvalid { 63 switch k { 64 case "r1": 65 fallthrough 66 case "r2": 67 fallthrough 68 case "r3": 69 if s1Cnt == 0 { 70 t.Errorf("cse removed all of r1,r2,r3") 71 } 72 s1Cnt-- 73 74 case "r4": 75 fallthrough 76 case "r5": 77 if s2Cnt == 0 { 78 t.Errorf("cse removed all of r4,r5") 79 } 80 s2Cnt-- 81 default: 82 t.Errorf("cse removed %s, but shouldn't have", k) 83 } 84 } 85 } 86 87 if s1Cnt != 0 || s2Cnt != 0 { 88 t.Errorf("%d values missed during cse", s1Cnt+s2Cnt) 89 } 90} 91 92// TestZCSE tests the zero arg cse. 93func TestZCSE(t *testing.T) { 94 c := testConfig(t) 95 a := c.Temp(c.config.Types.Int8.PtrTo()) 96 97 fun := c.Fun("entry", 98 Bloc("entry", 99 Valu("start", OpInitMem, types.TypeMem, 0, nil), 100 Valu("sp", OpSP, c.config.Types.Uintptr, 0, nil), 101 Valu("sb1", OpSB, c.config.Types.Uintptr, 0, nil), 102 Valu("sb2", OpSB, c.config.Types.Uintptr, 0, nil), 103 Valu("addr1", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sb1"), 104 Valu("addr2", OpAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sb2"), 105 Valu("a1ld", OpLoad, c.config.Types.Int64, 0, nil, "addr1", "start"), 106 Valu("a2ld", OpLoad, c.config.Types.Int64, 0, nil, "addr2", "start"), 107 Valu("c1", OpConst64, c.config.Types.Int64, 1, nil), 108 Valu("r1", OpAdd64, c.config.Types.Int64, 0, nil, "a1ld", "c1"), 109 Valu("c2", OpConst64, c.config.Types.Int64, 1, nil), 110 Valu("r2", OpAdd64, c.config.Types.Int64, 0, nil, "a2ld", "c2"), 111 Valu("r3", OpAdd64, c.config.Types.Int64, 0, nil, "r1", "r2"), 112 Valu("raddr", OpLocalAddr, c.config.Types.Int64.PtrTo(), 0, nil, "sp", "start"), 113 Valu("raddrdef", OpVarDef, types.TypeMem, 0, a, "start"), 114 Valu("rstore", OpStore, types.TypeMem, 0, c.config.Types.Int64, "raddr", "r3", "raddrdef"), 115 Goto("exit")), 116 Bloc("exit", 117 Exit("rstore"))) 118 119 CheckFunc(fun.f) 120 zcse(fun.f) 121 deadcode(fun.f) 122 CheckFunc(fun.f) 123 124 if fun.values["c1"].Op != OpInvalid && fun.values["c2"].Op != OpInvalid { 125 t.Errorf("zsce should have removed c1 or c2") 126 } 127 if fun.values["sb1"].Op != OpInvalid && fun.values["sb2"].Op != OpInvalid { 128 t.Errorf("zsce should have removed sb1 or sb2") 129 } 130} 131