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 }