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 (
      8 	"cmd/compile/internal/types"
      9 	"fmt"
     10 	"strconv"
     11 	"testing"
     12 )
     13 
     14 func 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 
     44 func 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 
     67 func 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 
    102 func 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 
    141 func 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