github.com/yukk001/go1.10.8@v0.0.0-20190813125351-6df2d3982e20/src/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 } 32 33 var szs = []szD{ 34 {name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0x8000000000000000, 0xffffFFFFffffFFFF}}, 35 {name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF, 36 -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}}, 37 38 {name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}}, 39 {name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0, 40 1, 0x7FFFFFFF}}, 41 42 {name: "uint16", sn: "16", u: []uint64{0, 1, 65535}}, 43 {name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}}, 44 45 {name: "uint8", sn: "8", u: []uint64{0, 1, 255}}, 46 {name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}}, 47 } 48 49 var ops = []op{ 50 {"add", "+"}, 51 {"sub", "-"}, 52 {"div", "/"}, 53 {"mul", "*"}, 54 {"lsh", "<<"}, 55 {"rsh", ">>"}, 56 {"mod", "%"}, 57 {"and", "&"}, 58 {"or", "|"}, 59 {"xor", "^"}, 60 } 61 62 // compute the result of i op j, cast as type t. 63 func ansU(i, j uint64, t, op string) string { 64 var ans uint64 65 switch op { 66 case "+": 67 ans = i + j 68 case "-": 69 ans = i - j 70 case "*": 71 ans = i * j 72 case "/": 73 if j != 0 { 74 ans = i / j 75 } 76 case "%": 77 if j != 0 { 78 ans = i % j 79 } 80 case "<<": 81 ans = i << j 82 case ">>": 83 ans = i >> j 84 case "&": 85 ans = i & j 86 case "|": 87 ans = i | j 88 case "^": 89 ans = i ^ j 90 } 91 switch t { 92 case "uint32": 93 ans = uint64(uint32(ans)) 94 case "uint16": 95 ans = uint64(uint16(ans)) 96 case "uint8": 97 ans = uint64(uint8(ans)) 98 } 99 return fmt.Sprintf("%d", ans) 100 } 101 102 // compute the result of i op j, cast as type t. 103 func ansS(i, j int64, t, op string) string { 104 var ans int64 105 switch op { 106 case "+": 107 ans = i + j 108 case "-": 109 ans = i - j 110 case "*": 111 ans = i * j 112 case "/": 113 if j != 0 { 114 ans = i / j 115 } 116 case "%": 117 if j != 0 { 118 ans = i % j 119 } 120 case "<<": 121 ans = i << uint64(j) 122 case ">>": 123 ans = i >> uint64(j) 124 case "&": 125 ans = i & j 126 case "|": 127 ans = i | j 128 case "^": 129 ans = i ^ j 130 } 131 switch t { 132 case "int32": 133 ans = int64(int32(ans)) 134 case "int16": 135 ans = int64(int16(ans)) 136 case "int8": 137 ans = int64(int8(ans)) 138 } 139 return fmt.Sprintf("%d", ans) 140 } 141 142 func main() { 143 w := new(bytes.Buffer) 144 fmt.Fprintf(w, "// run\n") 145 fmt.Fprintf(w, "// Code generated by gen/arithConstGen.go. DO NOT EDIT.\n\n") 146 fmt.Fprintf(w, "package main;\n") 147 fmt.Fprintf(w, "import \"fmt\"\n") 148 149 fncCnst1, err := template.New("fnc").Parse( 150 `//go:noinline 151 func {{.Name}}_{{.Type_}}_{{.FNumber}}_ssa(a {{.Type_}}) {{.Type_}} { 152 return a {{.Symbol}} {{.Number}} 153 } 154 `) 155 if err != nil { 156 panic(err) 157 } 158 fncCnst2, err := template.New("fnc").Parse( 159 `//go:noinline 160 func {{.Name}}_{{.FNumber}}_{{.Type_}}_ssa(a {{.Type_}}) {{.Type_}} { 161 return {{.Number}} {{.Symbol}} a 162 } 163 164 `) 165 if err != nil { 166 panic(err) 167 } 168 169 type fncData struct { 170 Name, Type_, Symbol, FNumber, Number string 171 } 172 173 for _, s := range szs { 174 for _, o := range ops { 175 fd := fncData{o.name, s.name, o.symbol, "", ""} 176 177 // unsigned test cases 178 if len(s.u) > 0 { 179 for _, i := range s.u { 180 fd.Number = fmt.Sprintf("%d", i) 181 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 182 183 // avoid division by zero 184 if o.name != "mod" && o.name != "div" || i != 0 { 185 // introduce uint64 cast for rhs shift operands 186 // if they are too large for default uint type 187 number := fd.Number 188 if (o.name == "lsh" || o.name == "rsh") && uint64(uint32(i)) != i { 189 fd.Number = fmt.Sprintf("uint64(%s)", number) 190 } 191 fncCnst1.Execute(w, fd) 192 fd.Number = number 193 } 194 195 fncCnst2.Execute(w, fd) 196 } 197 } 198 199 // signed test cases 200 if len(s.i) > 0 { 201 // don't generate tests for shifts by signed integers 202 if o.name == "lsh" || o.name == "rsh" { 203 continue 204 } 205 for _, i := range s.i { 206 fd.Number = fmt.Sprintf("%d", i) 207 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 208 209 // avoid division by zero 210 if o.name != "mod" && o.name != "div" || i != 0 { 211 fncCnst1.Execute(w, fd) 212 } 213 fncCnst2.Execute(w, fd) 214 } 215 } 216 } 217 } 218 219 fmt.Fprintf(w, "var failed bool\n\n") 220 fmt.Fprintf(w, "func main() {\n\n") 221 222 vrf1, _ := template.New("vrf1").Parse(` 223 if got := {{.Name}}_{{.FNumber}}_{{.Type_}}_ssa({{.Input}}); got != {{.Ans}} { 224 fmt.Printf("{{.Name}}_{{.Type_}} {{.Number}}%s{{.Input}} = %d, wanted {{.Ans}}\n", ` + "`{{.Symbol}}`" + `, got) 225 failed = true 226 } 227 `) 228 229 vrf2, _ := template.New("vrf2").Parse(` 230 if got := {{.Name}}_{{.Type_}}_{{.FNumber}}_ssa({{.Input}}); got != {{.Ans}} { 231 fmt.Printf("{{.Name}}_{{.Type_}} {{.Input}}%s{{.Number}} = %d, wanted {{.Ans}}\n", ` + "`{{.Symbol}}`" + `, got) 232 failed = true 233 } 234 `) 235 236 type cfncData struct { 237 Name, Type_, Symbol, FNumber, Number string 238 Ans, Input string 239 } 240 for _, s := range szs { 241 if len(s.u) > 0 { 242 for _, o := range ops { 243 fd := cfncData{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 err = vrf1.Execute(w, fd) 255 if err != nil { 256 panic(err) 257 } 258 } 259 260 if o.name != "mod" && o.name != "div" || i != 0 { 261 fd.Ans = ansU(j, i, s.name, o.symbol) 262 fd.Input = fmt.Sprintf("%d", j) 263 err = vrf2.Execute(w, fd) 264 if err != nil { 265 panic(err) 266 } 267 } 268 269 } 270 } 271 272 } 273 } 274 275 // signed 276 if len(s.i) > 0 { 277 for _, o := range ops { 278 // don't generate tests for shifts by signed integers 279 if o.name == "lsh" || o.name == "rsh" { 280 continue 281 } 282 fd := cfncData{o.name, s.name, o.symbol, "", "", "", ""} 283 for _, i := range s.i { 284 fd.Number = fmt.Sprintf("%d", i) 285 fd.FNumber = strings.Replace(fd.Number, "-", "Neg", -1) 286 for _, j := range s.i { 287 if o.name != "mod" && o.name != "div" || j != 0 { 288 fd.Ans = ansS(i, j, s.name, o.symbol) 289 fd.Input = fmt.Sprintf("%d", j) 290 err = vrf1.Execute(w, fd) 291 if 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 err = vrf2.Execute(w, fd) 300 if err != nil { 301 panic(err) 302 } 303 } 304 305 } 306 } 307 308 } 309 } 310 } 311 312 fmt.Fprintf(w, `if failed { 313 panic("tests failed") 314 } 315 `) 316 fmt.Fprintf(w, "}\n") 317 318 // gofmt result 319 b := w.Bytes() 320 src, err := format.Source(b) 321 if err != nil { 322 fmt.Printf("%s\n", b) 323 panic(err) 324 } 325 326 // write to file 327 err = ioutil.WriteFile("../arithConst.go", src, 0666) 328 if err != nil { 329 log.Fatalf("can't write output: %v\n", err) 330 } 331 }