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