• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5package ssa
6
7import (
8	"cmd/compile/internal/types"
9	"fmt"
10	"strconv"
11	"testing"
12)
13
14func TestDeadLoop(t *testing.T) {
15	c := testConfig(t)
16	fun := c.Fun("entry",
17		Bloc("entry",
18			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
19			Goto("exit")),
20		Bloc("exit",
21			Exit("mem")),
22		// dead loop
23		Bloc("deadblock",
24			// dead value in dead block
25			Valu("deadval", OpConstBool, c.config.Types.Bool, 1, nil),
26			If("deadval", "deadblock", "exit")))
27
28	CheckFunc(fun.f)
29	Deadcode(fun.f)
30	CheckFunc(fun.f)
31
32	for _, b := range fun.f.Blocks {
33		if b == fun.blocks["deadblock"] {
34			t.Errorf("dead block not removed")
35		}
36		for _, v := range b.Values {
37			if v == fun.values["deadval"] {
38				t.Errorf("control value of dead block not removed")
39			}
40		}
41	}
42}
43
44func TestDeadValue(t *testing.T) {
45	c := testConfig(t)
46	fun := c.Fun("entry",
47		Bloc("entry",
48			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
49			Valu("deadval", OpConst64, c.config.Types.Int64, 37, nil),
50			Goto("exit")),
51		Bloc("exit",
52			Exit("mem")))
53
54	CheckFunc(fun.f)
55	Deadcode(fun.f)
56	CheckFunc(fun.f)
57
58	for _, b := range fun.f.Blocks {
59		for _, v := range b.Values {
60			if v == fun.values["deadval"] {
61				t.Errorf("dead value not removed")
62			}
63		}
64	}
65}
66
67func TestNeverTaken(t *testing.T) {
68	c := testConfig(t)
69	fun := c.Fun("entry",
70		Bloc("entry",
71			Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil),
72			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
73			If("cond", "then", "else")),
74		Bloc("then",
75			Goto("exit")),
76		Bloc("else",
77			Goto("exit")),
78		Bloc("exit",
79			Exit("mem")))
80
81	CheckFunc(fun.f)
82	Opt(fun.f)
83	Deadcode(fun.f)
84	CheckFunc(fun.f)
85
86	if fun.blocks["entry"].Kind != BlockPlain {
87		t.Errorf("if(false) not simplified")
88	}
89	for _, b := range fun.f.Blocks {
90		if b == fun.blocks["then"] {
91			t.Errorf("then block still present")
92		}
93		for _, v := range b.Values {
94			if v == fun.values["cond"] {
95				t.Errorf("constant condition still present")
96			}
97		}
98	}
99
100}
101
102func TestNestedDeadBlocks(t *testing.T) {
103	c := testConfig(t)
104	fun := c.Fun("entry",
105		Bloc("entry",
106			Valu("mem", OpInitMem, types.TypeMem, 0, nil),
107			Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil),
108			If("cond", "b2", "b4")),
109		Bloc("b2",
110			If("cond", "b3", "b4")),
111		Bloc("b3",
112			If("cond", "b3", "b4")),
113		Bloc("b4",
114			If("cond", "b3", "exit")),
115		Bloc("exit",
116			Exit("mem")))
117
118	CheckFunc(fun.f)
119	Opt(fun.f)
120	CheckFunc(fun.f)
121	Deadcode(fun.f)
122	CheckFunc(fun.f)
123	if fun.blocks["entry"].Kind != BlockPlain {
124		t.Errorf("if(false) not simplified")
125	}
126	for _, b := range fun.f.Blocks {
127		if b == fun.blocks["b2"] {
128			t.Errorf("b2 block still present")
129		}
130		if b == fun.blocks["b3"] {
131			t.Errorf("b3 block still present")
132		}
133		for _, v := range b.Values {
134			if v == fun.values["cond"] {
135				t.Errorf("constant condition still present")
136			}
137		}
138	}
139}
140
141func BenchmarkDeadCode(b *testing.B) {
142	for _, n := range [...]int{1, 10, 100, 1000, 10000, 100000, 200000} {
143		b.Run(strconv.Itoa(n), func(b *testing.B) {
144			c := testConfig(b)
145			blocks := make([]bloc, 0, n+2)
146			blocks = append(blocks,
147				Bloc("entry",
148					Valu("mem", OpInitMem, types.TypeMem, 0, nil),
149					Goto("exit")))
150			blocks = append(blocks, Bloc("exit", Exit("mem")))
151			for i := 0; i < n; i++ {
152				blocks = append(blocks, Bloc(fmt.Sprintf("dead%d", i), Goto("exit")))
153			}
154			b.ResetTimer()
155			for i := 0; i < b.N; i++ {
156				fun := c.Fun("entry", blocks...)
157				Deadcode(fun.f)
158			}
159		})
160	}
161}
162