// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package ssa import ( "cmd/compile/internal/types" "fmt" "strconv" "testing" ) func TestDeadLoop(t *testing.T) { c := testConfig(t) fun := c.Fun("entry", Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem")), // dead loop Bloc("deadblock", // dead value in dead block Valu("deadval", OpConstBool, c.config.Types.Bool, 1, nil), If("deadval", "deadblock", "exit"))) CheckFunc(fun.f) Deadcode(fun.f) CheckFunc(fun.f) for _, b := range fun.f.Blocks { if b == fun.blocks["deadblock"] { t.Errorf("dead block not removed") } for _, v := range b.Values { if v == fun.values["deadval"] { t.Errorf("control value of dead block not removed") } } } } func TestDeadValue(t *testing.T) { c := testConfig(t) fun := c.Fun("entry", Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), Valu("deadval", OpConst64, c.config.Types.Int64, 37, nil), Goto("exit")), Bloc("exit", Exit("mem"))) CheckFunc(fun.f) Deadcode(fun.f) CheckFunc(fun.f) for _, b := range fun.f.Blocks { for _, v := range b.Values { if v == fun.values["deadval"] { t.Errorf("dead value not removed") } } } } func TestNeverTaken(t *testing.T) { c := testConfig(t) fun := c.Fun("entry", Bloc("entry", Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil), Valu("mem", OpInitMem, types.TypeMem, 0, nil), If("cond", "then", "else")), Bloc("then", Goto("exit")), Bloc("else", Goto("exit")), Bloc("exit", Exit("mem"))) CheckFunc(fun.f) Opt(fun.f) Deadcode(fun.f) CheckFunc(fun.f) if fun.blocks["entry"].Kind != BlockPlain { t.Errorf("if(false) not simplified") } for _, b := range fun.f.Blocks { if b == fun.blocks["then"] { t.Errorf("then block still present") } for _, v := range b.Values { if v == fun.values["cond"] { t.Errorf("constant condition still present") } } } } func TestNestedDeadBlocks(t *testing.T) { c := testConfig(t) fun := c.Fun("entry", Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil), If("cond", "b2", "b4")), Bloc("b2", If("cond", "b3", "b4")), Bloc("b3", If("cond", "b3", "b4")), Bloc("b4", If("cond", "b3", "exit")), Bloc("exit", Exit("mem"))) CheckFunc(fun.f) Opt(fun.f) CheckFunc(fun.f) Deadcode(fun.f) CheckFunc(fun.f) if fun.blocks["entry"].Kind != BlockPlain { t.Errorf("if(false) not simplified") } for _, b := range fun.f.Blocks { if b == fun.blocks["b2"] { t.Errorf("b2 block still present") } if b == fun.blocks["b3"] { t.Errorf("b3 block still present") } for _, v := range b.Values { if v == fun.values["cond"] { t.Errorf("constant condition still present") } } } } func BenchmarkDeadCode(b *testing.B) { for _, n := range [...]int{1, 10, 100, 1000, 10000, 100000, 200000} { b.Run(strconv.Itoa(n), func(b *testing.B) { c := testConfig(b) blocks := make([]bloc, 0, n+2) blocks = append(blocks, Bloc("entry", Valu("mem", OpInitMem, types.TypeMem, 0, nil), Goto("exit"))) blocks = append(blocks, Bloc("exit", Exit("mem"))) for i := 0; i < n; i++ { blocks = append(blocks, Bloc(fmt.Sprintf("dead%d", i), Goto("exit"))) } b.ResetTimer() for i := 0; i < b.N; i++ { fun := c.Fun("entry", blocks...) Deadcode(fun.f) } }) } }