github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/testdata/gen/arithConstGen.go (about) 1 // Copyright 2016 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 // This program generates a test to verify that the standard arithmetic 6 // operators properly handle const cases. The test file should be 7 // generated with a known working version of go. 8 // launch with `go run arithConstGen.go` a file called arithConst.go 9 // will be written into the parent directory containing the tests 10 11 package main 12 13 import ( 14 "bytes" 15 "fmt" 16 "go/format" 17 "io/ioutil" 18 "log" 19 "strings" 20 "text/template" 21 ) 22 23 type op struct { 24 name, symbol string 25 } 26 type szD struct { 27 name string 28 sn string 29 u []uint64 30 i []int64 31 oponly string 32 } 33 34 var szs = []szD{ 35 {name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0x8000000000000000, 0xffffFFFFffffFFFF}}, 36 {name: "uint64", sn: "64", u: []uint64{3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"}, 37 38 {name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF, 39 -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}}, 40 {name: "int64", sn: "64", i: []int64{-9, -5, -3, 3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"}, 41 42 {name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}}, 43 {name: "uint32", sn: "32", u: []uint64{3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"}, 44 45 {name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0, 46 1, 0x7FFFFFFF}}, 47 {name: "int32", sn: "32", i: []int64{-9, -5, -3, 3, 5, 7, 9, 10, 11, 13, 19, 21, 25, 27, 37, 41, 45, 73, 81}, oponly: "mul"}, 48 49 {name: "uint16", sn: "16", u: []uint64{0, 1, 65535}}, 50 {name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}}, 51 52 {name: "uint8", sn: "8", u: []uint64{0, 1, 255}}, 53 {name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}}, 54 } 55 56 var ops = []op{ 57 {"add", "+"}, 58 {"sub", "-"}, 59 {"div", "/"}, 60 {"mul", "*"}, 61 {"lsh", "<<"}, 62 {"rsh", ">>"}, 63 {"mod", "%"}, 64 {"and", "&"}, 65 {"or", "|"}, 66 {"xor", "^"}, 67 } 68 69 // compute the result of i op j, cast as type t. 70 func ansU(i, j uint64, t, op string) string { 71 var ans uint64 72 switch op { 73 case "+": 74 ans = i + j 75 case "-": 76 ans = i - j 77 case "*": 78 ans = i * j 79 case "/": 80 if j != 0 { 81 ans = i / j 82 } 83 case "%": 84 if j != 0 { 85 ans = i % j 86 } 87 case "<<": 88 ans = i << j 89 case ">>": 90 ans = i >> j 91 case "&": 92 ans = i & j 93 case "|": 94 ans = i | j 95 case "^": 96 ans = i ^ j 97 } 98 switch t { 99 case "uint32": 100 ans = uint64(uint32(ans)) 101 case "uint16": 102 ans = uint64(uint16(ans)) 103 case "uint8": 104 ans = uint64(uint8(ans)) 105 } 106 return fmt.Sprintf("%d", ans) 107 } 108 109 // compute the result of i op j, cast as type t. 110 func ansS(i, j int64, t, op string) string { 111 var ans int64 112 switch op { 113 case "+": 114 ans = i + j 115 case "-": 116 ans = i - j 117 case "*": 118 ans = i * j 119 case "/": 120 if j != 0 { 121 ans = i / j 122 } 123 case "%": 124 if j != 0 { 125 ans = i % j 126 } 127 case "<<": 128 ans = i << uint64(j) 129 case ">>": 130 ans = i >> uint64(j) 131 case "&": 132 ans = i & j 133 case "|": 134 ans = i | j 135 case "^": 136 ans = i ^ j 137 } 138 switch t { 139 case "int32": 140 ans = int64(int32(ans)) 141 case "int16": 142 ans = int64(int16(ans)) 143 case "int8": 144 ans = int64(int8(ans)) 145 } 146 return fmt.Sprintf("%d", ans) 147 } 148 149 func main() { 150 w := new(bytes.Buffer) 151 fmt.Fprintf(w, "// Code generated by gen/arithConstGen.go. DO NOT EDIT.\n\n") 152 fmt.Fprintf(w, "package main;\n") 153 fmt.Fprintf(w, "import \"testing\"\n") 154 155 fncCnst1 := template.Must(template.New("fnc").Parse( 156 `//go:noinline 157 func {{.Name}}_{{.Type_}}_{{.FNumber}}(a {{.Type_}}) {{.Type_}} { return a {{.Symbol}} {{.Number}} } 158 `)) 159 fncCnst2 := template.Must(template.New("fnc").Parse( 160 `//go:noinline 161 func {{.Name}}_{{.FNumber}}_{{.Type_}}(a {{.Type_}}) {{.Type_}} { return {{.Number}} {{.Symbol}} a } 162 `)) 163 164 type fncData struct { 165 Name, Type_, Symbol, FNumber, Number string 166 } 167 168 for _, s := range szs { 169 for _, o := range ops { 170 if s.oponly != "" && s.oponly != o.name { 171 continue 172 } 173 fd := fncData{o.name, s.name, o.symbol, "", ""} 174 175 // unsigned test cases 176 if len(s.u) > 0 { 177 for _, i := range s.u { 178 fd.Number = fmt.Sprintf("%d", i) 179 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 180 181 // avoid division by zero 182 if o.name != "mod" && o.name != "div" || i != 0 { 183 // introduce uint64 cast for rhs shift operands 184 // if they are too large for default uint type 185 number := fd.Number 186 if (o.name == "lsh" || o.name == "rsh") && uint64(uint32(i)) != i { 187 fd.Number = fmt.Sprintf("uint64(%s)", number) 188 } 189 fncCnst1.Execute(w, fd) 190 fd.Number = number 191 } 192 193 fncCnst2.Execute(w, fd) 194 } 195 } 196 197 // signed test cases 198 if len(s.i) > 0 { 199 // don't generate tests for shifts by signed integers 200 if o.name == "lsh" || o.name == "rsh" { 201 continue 202 } 203 for _, i := range s.i { 204 fd.Number = fmt.Sprintf("%d", i) 205 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 206 207 // avoid division by zero 208 if o.name != "mod" && o.name != "div" || i != 0 { 209 fncCnst1.Execute(w, fd) 210 } 211 fncCnst2.Execute(w, fd) 212 } 213 } 214 } 215 } 216 217 vrf1 := template.Must(template.New("vrf1").Parse(` 218 test_{{.Size}}{fn: {{.Name}}_{{.FNumber}}_{{.Type_}}, fnname: "{{.Name}}_{{.FNumber}}_{{.Type_}}", in: {{.Input}}, want: {{.Ans}}},`)) 219 220 vrf2 := template.Must(template.New("vrf2").Parse(` 221 test_{{.Size}}{fn: {{.Name}}_{{.Type_}}_{{.FNumber}}, fnname: "{{.Name}}_{{.Type_}}_{{.FNumber}}", in: {{.Input}}, want: {{.Ans}}},`)) 222 223 type cfncData struct { 224 Size, Name, Type_, Symbol, FNumber, Number string 225 Ans, Input string 226 } 227 for _, s := range szs { 228 fmt.Fprintf(w, ` 229 type test_%[1]s%[2]s struct { 230 fn func (%[1]s) %[1]s 231 fnname string 232 in %[1]s 233 want %[1]s 234 } 235 `, s.name, s.oponly) 236 fmt.Fprintf(w, "var tests_%[1]s%[2]s =[]test_%[1]s {\n\n", s.name, s.oponly) 237 238 if len(s.u) > 0 { 239 for _, o := range ops { 240 if s.oponly != "" && s.oponly != o.name { 241 continue 242 } 243 fd := cfncData{s.name, o.name, s.name, o.symbol, "", "", "", ""} 244 for _, i := range s.u { 245 fd.Number = fmt.Sprintf("%d", i) 246 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 247 248 // unsigned 249 for _, j := range s.u { 250 251 if o.name != "mod" && o.name != "div" || j != 0 { 252 fd.Ans = ansU(i, j, s.name, o.symbol) 253 fd.Input = fmt.Sprintf("%d", j) 254 if err := vrf1.Execute(w, fd); err != nil { 255 panic(err) 256 } 257 } 258 259 if o.name != "mod" && o.name != "div" || i != 0 { 260 fd.Ans = ansU(j, i, s.name, o.symbol) 261 fd.Input = fmt.Sprintf("%d", j) 262 if err := vrf2.Execute(w, fd); err != nil { 263 panic(err) 264 } 265 } 266 267 } 268 } 269 270 } 271 } 272 273 // signed 274 if len(s.i) > 0 { 275 for _, o := range ops { 276 if s.oponly != "" && s.oponly != o.name { 277 continue 278 } 279 // don't generate tests for shifts by signed integers 280 if o.name == "lsh" || o.name == "rsh" { 281 continue 282 } 283 fd := cfncData{s.name, o.name, s.name, o.symbol, "", "", "", ""} 284 for _, i := range s.i { 285 fd.Number = fmt.Sprintf("%d", i) 286 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 287 for _, j := range s.i { 288 if o.name != "mod" && o.name != "div" || j != 0 { 289 fd.Ans = ansS(i, j, s.name, o.symbol) 290 fd.Input = fmt.Sprintf("%d", j) 291 if err := vrf1.Execute(w, fd); err != nil { 292 panic(err) 293 } 294 } 295 296 if o.name != "mod" && o.name != "div" || i != 0 { 297 fd.Ans = ansS(j, i, s.name, o.symbol) 298 fd.Input = fmt.Sprintf("%d", j) 299 if err := vrf2.Execute(w, fd); err != nil { 300 panic(err) 301 } 302 } 303 304 } 305 } 306 307 } 308 } 309 310 fmt.Fprintf(w, "}\n\n") 311 } 312 313 fmt.Fprint(w, ` 314 315 // TestArithmeticConst tests results for arithmetic operations against constants. 316 func TestArithmeticConst(t *testing.T) { 317 `) 318 319 for _, s := range szs { 320 fmt.Fprintf(w, `for _, test := range tests_%s%s {`, s.name, s.oponly) 321 // Use WriteString here to avoid a vet warning about formatting directives. 322 w.WriteString(`if got := test.fn(test.in); got != test.want { 323 t.Errorf("%s(%d) = %d, want %d\n", test.fnname, test.in, got, test.want) 324 } 325 } 326 `) 327 } 328 329 fmt.Fprint(w, ` 330 } 331 `) 332 333 // gofmt result 334 b := w.Bytes() 335 src, err := format.Source(b) 336 if err != nil { 337 fmt.Printf("%s\n", b) 338 panic(err) 339 } 340 341 // write to file 342 err = ioutil.WriteFile("../arithConst_test.go", src, 0666) 343 if err != nil { 344 log.Fatalf("can't write output: %v\n", err) 345 } 346 }