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