1
2
3
4
5
6
7
8
9
10
11 package main
12
13 import (
14 "bytes"
15 "fmt"
16 "go/format"
17 "io/ioutil"
18 "log"
19 "text/template"
20 )
21
22
23 type tmplData struct {
24 Name, Stype, Symbol string
25 }
26
27
28
29 func (s tmplData) SymFirst() string {
30 return string(s.Symbol[0])
31 }
32
33
34 func ucast(i uint64, s sizedTestData) uint64 {
35 switch s.name {
36 case "uint32":
37 return uint64(uint32(i))
38 case "uint16":
39 return uint64(uint16(i))
40 case "uint8":
41 return uint64(uint8(i))
42 }
43 return i
44 }
45
46
47 func icast(i int64, s sizedTestData) int64 {
48 switch s.name {
49 case "int32":
50 return int64(int32(i))
51 case "int16":
52 return int64(int16(i))
53 case "int8":
54 return int64(int8(i))
55 }
56 return i
57 }
58
59 type sizedTestData struct {
60 name string
61 sn string
62 u []uint64
63 i []int64
64 }
65
66
67
68
69 var szs = []sizedTestData{
70 sizedTestData{name: "uint64", sn: "64", u: []uint64{0, 1, 4294967296, 0xffffFFFFffffFFFF}},
71 sizedTestData{name: "int64", sn: "64", i: []int64{-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
72 -4294967296, -1, 0, 1, 4294967296, 0x7FFFFFFFFFFFFFFE, 0x7FFFFFFFFFFFFFFF}},
73
74 sizedTestData{name: "uint32", sn: "32", u: []uint64{0, 1, 4294967295}},
75 sizedTestData{name: "int32", sn: "32", i: []int64{-0x80000000, -0x7FFFFFFF, -1, 0,
76 1, 0x7FFFFFFF}},
77
78 sizedTestData{name: "uint16", sn: "16", u: []uint64{0, 1, 65535}},
79 sizedTestData{name: "int16", sn: "16", i: []int64{-32768, -32767, -1, 0, 1, 32766, 32767}},
80
81 sizedTestData{name: "uint8", sn: "8", u: []uint64{0, 1, 255}},
82 sizedTestData{name: "int8", sn: "8", i: []int64{-128, -127, -1, 0, 1, 126, 127}},
83 }
84
85 type op struct {
86 name, symbol string
87 }
88
89
90 var ops = []op{op{"add", "+"}, op{"sub", "-"}, op{"div", "/"}, op{"mod", "%%"}, op{"mul", "*"}}
91
92 func main() {
93 w := new(bytes.Buffer)
94 fmt.Fprintf(w, "// Code generated by gen/arithBoundaryGen.go. DO NOT EDIT.\n\n")
95 fmt.Fprintf(w, "package main;\n")
96 fmt.Fprintf(w, "import \"testing\"\n")
97
98 for _, sz := range []int{64, 32, 16, 8} {
99 fmt.Fprintf(w, "type utd%d struct {\n", sz)
100 fmt.Fprintf(w, " a,b uint%d\n", sz)
101 fmt.Fprintf(w, " add,sub,mul,div,mod uint%d\n", sz)
102 fmt.Fprintf(w, "}\n")
103
104 fmt.Fprintf(w, "type itd%d struct {\n", sz)
105 fmt.Fprintf(w, " a,b int%d\n", sz)
106 fmt.Fprintf(w, " add,sub,mul,div,mod int%d\n", sz)
107 fmt.Fprintf(w, "}\n")
108 }
109
110
111 testFunc, err := template.New("testFunc").Parse(
112 `//go:noinline
113 func {{.Name}}_{{.Stype}}_ssa(a, b {{.Stype}}) {{.Stype}} {
114 return a {{.SymFirst}} b
115 }
116 `)
117 if err != nil {
118 panic(err)
119 }
120
121
122 for _, s := range szs {
123 for _, o := range ops {
124 fd := tmplData{o.name, s.name, o.symbol}
125 err = testFunc.Execute(w, fd)
126 if err != nil {
127 panic(err)
128 }
129 }
130 }
131
132
133 for _, s := range szs {
134 if len(s.u) > 0 {
135 fmt.Fprintf(w, "var %s_data []utd%s = []utd%s{", s.name, s.sn, s.sn)
136 for _, i := range s.u {
137 for _, j := range s.u {
138 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))
139 if j != 0 {
140 fmt.Fprintf(w, ", div: %d, mod: %d", ucast(i/j, s), ucast(i%j, s))
141 }
142 fmt.Fprint(w, "},\n")
143 }
144 }
145 fmt.Fprintf(w, "}\n")
146 } else {
147
148 fmt.Fprintf(w, "var %s_data []itd%s = []itd%s{", s.name, s.sn, s.sn)
149 for _, i := range s.i {
150 for _, j := range s.i {
151 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))
152 if j != 0 {
153 fmt.Fprintf(w, ", div: %d, mod: %d", icast(i/j, s), icast(i%j, s))
154 }
155 fmt.Fprint(w, "},\n")
156 }
157 }
158 fmt.Fprintf(w, "}\n")
159 }
160 }
161
162 fmt.Fprintf(w, "//TestArithmeticBoundary tests boundary results for arithmetic operations.\n")
163 fmt.Fprintf(w, "func TestArithmeticBoundary(t *testing.T) {\n\n")
164
165 verify, err := template.New("tst").Parse(
166 `if got := {{.Name}}_{{.Stype}}_ssa(v.a, v.b); got != v.{{.Name}} {
167 t.Errorf("{{.Name}}_{{.Stype}} %d{{.Symbol}}%d = %d, wanted %d\n",v.a,v.b,got,v.{{.Name}})
168 }
169 `)
170
171 for _, s := range szs {
172 fmt.Fprintf(w, "for _, v := range %s_data {\n", s.name)
173
174 for _, o := range ops {
175
176 if o.name == "div" || o.name == "mod" {
177 fmt.Fprint(w, "if v.b != 0 {")
178 }
179
180 err = verify.Execute(w, tmplData{o.name, s.name, o.symbol})
181
182 if o.name == "div" || o.name == "mod" {
183 fmt.Fprint(w, "\n}\n")
184 }
185
186 if err != nil {
187 panic(err)
188 }
189
190 }
191 fmt.Fprint(w, " }\n")
192 }
193
194 fmt.Fprintf(w, "}\n")
195
196
197 b := w.Bytes()
198 src, err := format.Source(b)
199 if err != nil {
200 fmt.Printf("%s\n", b)
201 panic(err)
202 }
203
204
205 err = ioutil.WriteFile("../arithBoundary_test.go", src, 0666)
206 if err != nil {
207 log.Fatalf("can't write output: %v\n", err)
208 }
209 }
210
View as plain text