...

Source file src/cmd/compile/internal/inline/inlheur/texpr_classify_test.go

Documentation: cmd/compile/internal/inline/inlheur

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

View as plain text