github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/test/testdata/gen/arithBoundaryGen.go (about) 1 // Copyright 2015 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 some special cases. The test file should be 7 // generated with a known working version of go. 8 // launch with `go run arithBoundaryGen.go` a file called arithBoundary.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 "log" 18 "text/template" 19 ) 20 21 // used for interpolation in a text template 22 type tmplData struct { 23 Name, Stype, Symbol string 24 } 25 26 // used to work around an issue with the mod symbol being 27 // interpreted as part of a format string 28 func (s tmplData) SymFirst() string { 29 return string(s.Symbol[0]) 30 } 31 32 // ucast casts an unsigned int to the size in s 33 func ucast(i uint64, s sizedTestData) uint64 { 34 switch s.name { 35 case "uint32": 36 return uint64(uint32(i)) 37 case "uint16": 38 return uint64(uint16(i)) 39 case "uint8": 40 return uint64(uint8(i)) 41 } 42 return i 43 } 44 45 // icast casts a signed int to the size in s 46 func icast(i int64, s sizedTestData) int64 { 47 switch s.name { 48 case "int32": 49 return int64(int32(i)) 50 case "int16": 51 return int64(int16(i)) 52 case "int8": 53 return int64(int8(i)) 54 } 55 return i 56 } 57 58 type sizedTestData struct { 59 name string 60 sn string 61 u []uint64 62 i []int64 63 } 64 65 // values to generate tests. these should include the smallest and largest values, along 66 // with any other values that might cause issues. we generate n^2 tests for each size to 67 // cover all cases. 68 var szs = []sizedTestData{ 69 sizedTestData{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}}, 70 sizedTestData{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF, 71 -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}}, 72 73 sizedTestData{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}}, 74 sizedTestData{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0, 75 1, 0x7FFFFFFF}}, 76 77 sizedTestData{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}}, 78 sizedTestData{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}}, 79 80 sizedTestData{name: "uint8", sn: "8", u: []uint64{0, 1, 255}}, 81 sizedTestData{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}}, 82 } 83 84 type op struct { 85 name, symbol string 86 } 87 88 // ops that we will be generating tests for 89 var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, op{"mul", "*"}} 90 91 func main() { 92 w := new(bytes.Buffer) 93 fmt.Fprintf(w, "// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.\n\n") 94 fmt.Fprintf(w, "package main;\n") 95 fmt.Fprintf(w, "import \"testing\"\n") 96 97 for _, sz := range []int{64, 32, 16, 8} { 98 fmt.Fprintf(w, "type utd%d struct {\n", sz) 99 fmt.Fprintf(w, " a,b uint%d\n", sz) 100 fmt.Fprintf(w, " add,sub,mul,div,mod uint%d\n", sz) 101 fmt.Fprintf(w, "}\n") 102 103 fmt.Fprintf(w, "type itd%d struct {\n", sz) 104 fmt.Fprintf(w, " a,b int%d\n", sz) 105 fmt.Fprintf(w, " add,sub,mul,div,mod int%d\n", sz) 106 fmt.Fprintf(w, "}\n") 107 } 108 109 // the function being tested 110 testFunc, err := template.New("testFunc").Parse( 111 `//go:noinline 112 func {{.Name}}_{{.Stype}}_ssa(a, b {{.Stype}}) {{.Stype}} { 113 return a {{.SymFirst}} b 114 } 115 `) 116 if err != nil { 117 panic(err) 118 } 119 120 // generate our functions to be tested 121 for _, s := range szs { 122 for _, o := range ops { 123 fd := tmplData{o.name, s.name, o.symbol} 124 err = testFunc.Execute(w, fd) 125 if err != nil { 126 panic(err) 127 } 128 } 129 } 130 131 // generate the test data 132 for _, s := range szs { 133 if len(s.u) > 0 { 134 fmt.Fprintf(w, "var %s_data []utd%s = []utd%s{", s.name, s.sn, s.sn) 135 for _, i := range s.u { 136 for _, j := range s.u { 137 fmt.Fprintf(w, "utd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, ucast(i+j, s), ucast(i-j, s), ucast(i*j, s)) 138 if j != 0 { 139 fmt.Fprintf(w, ", div: %d, mod: %d", ucast(i/j, s), ucast(i%j, s)) 140 } 141 fmt.Fprint(w, "},\n") 142 } 143 } 144 fmt.Fprintf(w, "}\n") 145 } else { 146 // TODO: clean up this duplication 147 fmt.Fprintf(w, "var %s_data []itd%s = []itd%s{", s.name, s.sn, s.sn) 148 for _, i := range s.i { 149 for _, j := range s.i { 150 fmt.Fprintf(w, "itd%s{a: %d, b: %d, add: %d, sub: %d, mul: %d", s.sn, i, j, icast(i+j, s), icast(i-j, s), icast(i*j, s)) 151 if j != 0 { 152 fmt.Fprintf(w, ", div: %d, mod: %d", icast(i/j, s), icast(i%j, s)) 153 } 154 fmt.Fprint(w, "},\n") 155 } 156 } 157 fmt.Fprintf(w, "}\n") 158 } 159 } 160 161 fmt.Fprintf(w, "//TestArithmeticBoundary tests boundary results for arithmetic operations.\n") 162 fmt.Fprintf(w, "func TestArithmeticBoundary(t *testing.T) {\n\n") 163 164 verify, err := template.New("tst").Parse( 165 `if got := {{.Name}}_{{.Stype}}_ssa(v.a, v.b); got != v.{{.Name}} { 166 t.Errorf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}}) 167 } 168 `) 169 170 for _, s := range szs { 171 fmt.Fprintf(w, "for _, v := range %s_data {\n", s.name) 172 173 for _, o := range ops { 174 // avoid generating tests that divide by zero 175 if o.name == "div" || o.name == "mod" { 176 fmt.Fprint(w, "if v.b != 0 {") 177 } 178 179 err = verify.Execute(w, tmplData{o.name, s.name, o.symbol}) 180 181 if o.name == "div" || o.name == "mod" { 182 fmt.Fprint(w, "\n}\n") 183 } 184 185 if err != nil { 186 panic(err) 187 } 188 189 } 190 fmt.Fprint(w, " }\n") 191 } 192 193 fmt.Fprintf(w, "}\n") 194 195 // gofmt result 196 b := w.Bytes() 197 src, err := format.Source(b) 198 if err != nil { 199 fmt.Printf("%s\n", b) 200 panic(err) 201 } 202 203 // write to file 204 err = os.WriteFile("../arithBoundary_test.go", src, 0666) 205 if err != nil { 206 log.Fatalf("can't write output: %v\n", err) 207 } 208 }