github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ssa/deadcode_test.go (about)

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