github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/inline/inlheur/texpr_classify_test.go (about)

     1  // Copyright 2023 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 inlheur
     6  
     7  import (
     8  	"go/constant"
     9  	"testing"
    10  
    11  	"github.com/go-asm/go/cmd/compile/ir"
    12  	"github.com/go-asm/go/cmd/compile/typecheck"
    13  	"github.com/go-asm/go/cmd/compile/types"
    14  	"github.com/go-asm/go/cmd/src"
    15  )
    16  
    17  var pos src.XPos
    18  var local *types.Pkg
    19  var f *ir.Func
    20  
    21  func init() {
    22  	types.PtrSize = 8
    23  	types.RegSize = 8
    24  	types.MaxWidth = 1 << 50
    25  	typecheck.InitUniverse()
    26  	local = types.NewPkg("", "")
    27  	fsym := &types.Sym{
    28  		Pkg:  types.NewPkg("my/import/path", "path"),
    29  		Name: "function",
    30  	}
    31  	f = ir.NewFunc(src.NoXPos, src.NoXPos, fsym, nil)
    32  }
    33  
    34  type state struct {
    35  	ntab map[string]*ir.Name
    36  }
    37  
    38  func mkstate() *state {
    39  	return &state{
    40  		ntab: make(map[string]*ir.Name),
    41  	}
    42  }
    43  
    44  func bin(x ir.Node, op ir.Op, y ir.Node) ir.Node {
    45  	return ir.NewBinaryExpr(pos, op, x, y)
    46  }
    47  
    48  func conv(x ir.Node, t *types.Type) ir.Node {
    49  	return ir.NewConvExpr(pos, ir.OCONV, t, x)
    50  }
    51  
    52  func logical(x ir.Node, op ir.Op, y ir.Node) ir.Node {
    53  	return ir.NewLogicalExpr(pos, op, x, y)
    54  }
    55  
    56  func un(op ir.Op, x ir.Node) ir.Node {
    57  	return ir.NewUnaryExpr(pos, op, x)
    58  }
    59  
    60  func liti(i int64) ir.Node {
    61  	return ir.NewBasicLit(pos, types.Types[types.TINT64], constant.MakeInt64(i))
    62  }
    63  
    64  func lits(s string) ir.Node {
    65  	return ir.NewBasicLit(pos, types.Types[types.TSTRING], constant.MakeString(s))
    66  }
    67  
    68  func (s *state) nm(name string, t *types.Type) *ir.Name {
    69  	if n, ok := s.ntab[name]; ok {
    70  		if n.Type() != t {
    71  			panic("bad")
    72  		}
    73  		return n
    74  	}
    75  	sym := local.Lookup(name)
    76  	nn := ir.NewNameAt(pos, sym, t)
    77  	s.ntab[name] = nn
    78  	return nn
    79  }
    80  
    81  func (s *state) nmi64(name string) *ir.Name {
    82  	return s.nm(name, types.Types[types.TINT64])
    83  }
    84  
    85  func (s *state) nms(name string) *ir.Name {
    86  	return s.nm(name, types.Types[types.TSTRING])
    87  }
    88  
    89  func TestClassifyIntegerCompare(t *testing.T) {
    90  
    91  	// (n < 10 || n > 100) && (n >= 12 || n <= 99 || n != 101)
    92  	s := mkstate()
    93  	nn := s.nmi64("n")
    94  	nlt10 := bin(nn, ir.OLT, liti(10))         // n < 10
    95  	ngt100 := bin(nn, ir.OGT, liti(100))       // n > 100
    96  	nge12 := bin(nn, ir.OGE, liti(12))         // n >= 12
    97  	nle99 := bin(nn, ir.OLE, liti(99))         // n < 10
    98  	nne101 := bin(nn, ir.ONE, liti(101))       // n != 101
    99  	noror1 := logical(nlt10, ir.OOROR, ngt100) // n < 10 || n > 100
   100  	noror2 := logical(nge12, ir.OOROR, nle99)  // n >= 12 || n <= 99
   101  	noror3 := logical(noror2, ir.OOROR, nne101)
   102  	nandand := typecheck.Expr(logical(noror1, ir.OANDAND, noror3))
   103  
   104  	wantv := true
   105  	v := ShouldFoldIfNameConstant(nandand, []*ir.Name{nn})
   106  	if v != wantv {
   107  		t.Errorf("wanted shouldfold(%v) %v, got %v", nandand, wantv, v)
   108  	}
   109  }
   110  
   111  func TestClassifyStringCompare(t *testing.T) {
   112  
   113  	// s != "foo" && s < "ooblek" && s > "plarkish"
   114  	s := mkstate()
   115  	nn := s.nms("s")
   116  	snefoo := bin(nn, ir.ONE, lits("foo"))     // s != "foo"
   117  	sltoob := bin(nn, ir.OLT, lits("ooblek"))  // s < "ooblek"
   118  	sgtpk := bin(nn, ir.OGT, lits("plarkish")) // s > "plarkish"
   119  	nandand := logical(snefoo, ir.OANDAND, sltoob)
   120  	top := typecheck.Expr(logical(nandand, ir.OANDAND, sgtpk))
   121  
   122  	wantv := true
   123  	v := ShouldFoldIfNameConstant(top, []*ir.Name{nn})
   124  	if v != wantv {
   125  		t.Errorf("wanted shouldfold(%v) %v, got %v", top, wantv, v)
   126  	}
   127  }
   128  
   129  func TestClassifyIntegerArith(t *testing.T) {
   130  	// n+1 ^ n-3 * n/2 + n<<9 + n>>2 - n&^7
   131  
   132  	s := mkstate()
   133  	nn := s.nmi64("n")
   134  	np1 := bin(nn, ir.OADD, liti(1))     // n+1
   135  	nm3 := bin(nn, ir.OSUB, liti(3))     // n-3
   136  	nd2 := bin(nn, ir.ODIV, liti(2))     // n/2
   137  	nls9 := bin(nn, ir.OLSH, liti(9))    // n<<9
   138  	nrs2 := bin(nn, ir.ORSH, liti(2))    // n>>2
   139  	nan7 := bin(nn, ir.OANDNOT, liti(7)) // n&^7
   140  	c1xor := bin(np1, ir.OXOR, nm3)
   141  	c2mul := bin(c1xor, ir.OMUL, nd2)
   142  	c3add := bin(c2mul, ir.OADD, nls9)
   143  	c4add := bin(c3add, ir.OADD, nrs2)
   144  	c5sub := bin(c4add, ir.OSUB, nan7)
   145  	top := typecheck.Expr(c5sub)
   146  
   147  	wantv := true
   148  	v := ShouldFoldIfNameConstant(top, []*ir.Name{nn})
   149  	if v != wantv {
   150  		t.Errorf("wanted shouldfold(%v) %v, got %v", top, wantv, v)
   151  	}
   152  }
   153  
   154  func TestClassifyAssortedShifts(t *testing.T) {
   155  
   156  	s := mkstate()
   157  	nn := s.nmi64("n")
   158  	badcases := []ir.Node{
   159  		bin(liti(3), ir.OLSH, nn), // 3<<n
   160  		bin(liti(7), ir.ORSH, nn), // 7>>n
   161  	}
   162  	for _, bc := range badcases {
   163  		wantv := false
   164  		v := ShouldFoldIfNameConstant(typecheck.Expr(bc), []*ir.Name{nn})
   165  		if v != wantv {
   166  			t.Errorf("wanted shouldfold(%v) %v, got %v", bc, wantv, v)
   167  		}
   168  	}
   169  }
   170  
   171  func TestClassifyFloat(t *testing.T) {
   172  	// float32(n) + float32(10)
   173  	s := mkstate()
   174  	nn := s.nm("n", types.Types[types.TUINT32])
   175  	f1 := conv(nn, types.Types[types.TFLOAT32])
   176  	f2 := conv(liti(10), types.Types[types.TFLOAT32])
   177  	add := bin(f1, ir.OADD, f2)
   178  
   179  	wantv := false
   180  	v := ShouldFoldIfNameConstant(typecheck.Expr(add), []*ir.Name{nn})
   181  	if v != wantv {
   182  		t.Errorf("wanted shouldfold(%v) %v, got %v", add, wantv, v)
   183  	}
   184  }
   185  
   186  func TestMultipleNamesAllUsed(t *testing.T) {
   187  	// n != 101 && m < 2
   188  	s := mkstate()
   189  	nn := s.nmi64("n")
   190  	nm := s.nmi64("m")
   191  	nne101 := bin(nn, ir.ONE, liti(101)) // n != 101
   192  	mlt2 := bin(nm, ir.OLT, liti(2))     // m < 2
   193  	nandand := typecheck.Expr(logical(nne101, ir.OANDAND, mlt2))
   194  
   195  	// all names used
   196  	wantv := true
   197  	v := ShouldFoldIfNameConstant(nandand, []*ir.Name{nn, nm})
   198  	if v != wantv {
   199  		t.Errorf("wanted shouldfold(%v) %v, got %v", nandand, wantv, v)
   200  	}
   201  
   202  	// not all names used
   203  	wantv = false
   204  	v = ShouldFoldIfNameConstant(nne101, []*ir.Name{nn, nm})
   205  	if v != wantv {
   206  		t.Errorf("wanted shouldfold(%v) %v, got %v", nne101, wantv, v)
   207  	}
   208  
   209  	// other names used.
   210  	np := s.nmi64("p")
   211  	pne0 := bin(np, ir.ONE, liti(101)) // p != 0
   212  	noror := logical(nandand, ir.OOROR, pne0)
   213  	wantv = false
   214  	v = ShouldFoldIfNameConstant(noror, []*ir.Name{nn, nm})
   215  	if v != wantv {
   216  		t.Errorf("wanted shouldfold(%v) %v, got %v", noror, wantv, v)
   217  	}
   218  }