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 "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
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
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
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
182 if o.name != "mod" && o.name != "div" || i != 0 {
183
184
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
198 if len(s.i) > 0 {
199
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
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
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
274 if len(s.i) > 0 {
275 for _, o := range ops {
276 if s.oponly != "" && s.oponly != o.name {
277 continue
278 }
279
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
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
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
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 }
347
View as plain text