1// runoutput
2
3// Copyright 2015 The Go Authors. All rights reserved.
4// Use of this source code is governed by a BSD-style
5// license that can be found in the LICENSE file.
6
7// terribly slow on wasm
8//go:build !wasm
9
10package main
11
12import (
13	"fmt"
14	"math/big"
15	"unsafe"
16)
17
18var one = big.NewInt(1)
19
20type _type struct {
21	name   string
22	bits   uint
23	signed bool
24}
25
26// testvalues returns a list of all test values for this type.
27func (t *_type) testvalues() []*big.Int {
28	var a []*big.Int
29
30	a = append(a, big.NewInt(0))
31	a = append(a, big.NewInt(1))
32	a = append(a, big.NewInt(2))
33	if t.signed {
34		a = append(a, big.NewInt(-1))
35		a = append(a, big.NewInt(-2))
36		r := big.NewInt(1)
37		a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(1)))
38		r = big.NewInt(1)
39		a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(2)))
40		r = big.NewInt(1)
41		a = append(a, r.Lsh(r, t.bits-1).Neg(r))
42		r = big.NewInt(1)
43		a = append(a, r.Lsh(r, t.bits-1).Neg(r).Add(r, big.NewInt(1)))
44	} else {
45		r := big.NewInt(1)
46		a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(1)))
47		r = big.NewInt(1)
48		a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(2)))
49	}
50	return a
51}
52
53// trunc truncates a value to the range of the given type.
54func (t *_type) trunc(x *big.Int) *big.Int {
55	r := new(big.Int)
56	m := new(big.Int)
57	m.Lsh(one, t.bits)
58	m.Sub(m, one)
59	r.And(x, m)
60	if t.signed && r.Bit(int(t.bits)-1) == 1 {
61		m.Neg(one)
62		m.Lsh(m, t.bits)
63		r.Or(r, m)
64	}
65	return r
66}
67
68var types = []_type{
69	_type{"byte", 8, false},
70	_type{"int8", 8, true},
71	_type{"uint8", 8, false},
72	_type{"rune", 32, true},
73	_type{"int16", 16, true},
74	_type{"uint16", 16, false},
75	_type{"int32", 32, true},
76	_type{"uint32", 32, false},
77	_type{"int64", 64, true},
78	_type{"uint64", 64, false},
79	_type{"int", 8 * uint(unsafe.Sizeof(int(0))), true},
80	_type{"uint", 8 * uint(unsafe.Sizeof(uint(0))), false},
81	_type{"uintptr", 8 * uint(unsafe.Sizeof((*byte)(nil))), false},
82}
83
84type binop struct {
85	name string
86	eval func(x, y *big.Int) *big.Int
87}
88
89var binops = []binop{
90	binop{"+", func(x, y *big.Int) *big.Int { return new(big.Int).Add(x, y) }},
91	binop{"-", func(x, y *big.Int) *big.Int { return new(big.Int).Sub(x, y) }},
92	binop{"*", func(x, y *big.Int) *big.Int { return new(big.Int).Mul(x, y) }},
93	binop{"/", func(x, y *big.Int) *big.Int { return new(big.Int).Quo(x, y) }},
94	binop{"%", func(x, y *big.Int) *big.Int { return new(big.Int).Rem(x, y) }},
95	binop{"&", func(x, y *big.Int) *big.Int { return new(big.Int).And(x, y) }},
96	binop{"|", func(x, y *big.Int) *big.Int { return new(big.Int).Or(x, y) }},
97	binop{"^", func(x, y *big.Int) *big.Int { return new(big.Int).Xor(x, y) }},
98	binop{"&^", func(x, y *big.Int) *big.Int { return new(big.Int).AndNot(x, y) }},
99}
100
101type unop struct {
102	name string
103	eval func(x *big.Int) *big.Int
104}
105
106var unops = []unop{
107	unop{"+", func(x *big.Int) *big.Int { return new(big.Int).Set(x) }},
108	unop{"-", func(x *big.Int) *big.Int { return new(big.Int).Neg(x) }},
109	unop{"^", func(x *big.Int) *big.Int { return new(big.Int).Not(x) }},
110}
111
112type shiftop struct {
113	name string
114	eval func(x *big.Int, i uint) *big.Int
115}
116
117var shiftops = []shiftop{
118	shiftop{"<<", func(x *big.Int, i uint) *big.Int { return new(big.Int).Lsh(x, i) }},
119	shiftop{">>", func(x *big.Int, i uint) *big.Int { return new(big.Int).Rsh(x, i) }},
120}
121
122// valname returns the name of n as can be used as part of a variable name.
123func valname(n *big.Int) string {
124	s := fmt.Sprintf("%d", n)
125	if s[0] == '-' {
126		s = "neg" + s[1:]
127	}
128	return s
129}
130
131func main() {
132	fmt.Println("package main")
133
134	// We make variables to hold all the different values we'd like to use.
135	// We use global variables to prevent any constant folding.
136	for _, t := range types {
137		for _, n := range t.testvalues() {
138			fmt.Printf("var %s_%s %s = %d\n", t.name, valname(n), t.name, n)
139		}
140	}
141
142	fmt.Println("func main() {")
143
144	for _, t := range types {
145		// test binary ops
146		for _, op := range binops {
147			for _, x := range t.testvalues() {
148				for _, y := range t.testvalues() {
149					if (op.name == "/" || op.name == "%") && y.Sign() == 0 {
150						continue
151					}
152					r := t.trunc(op.eval(x, y))
153					eqn := fmt.Sprintf("%s_%s %s %s_%s != %d", t.name, valname(x), op.name, t.name, valname(y), r)
154					fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
155				}
156			}
157		}
158		// test unary ops
159		for _, op := range unops {
160			for _, x := range t.testvalues() {
161				r := t.trunc(op.eval(x))
162				eqn := fmt.Sprintf("%s %s_%s != %d", op.name, t.name, valname(x), r)
163				fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
164			}
165		}
166		// test shifts
167		for _, op := range shiftops {
168			for _, x := range t.testvalues() {
169
170				for _, i := range []uint{0, 1, t.bits - 2, t.bits - 1, t.bits, t.bits + 1} {
171					r := t.trunc(op.eval(x, i))
172					eqn := fmt.Sprintf("%s_%s %s %d != %d", t.name, valname(x), op.name, i, r)
173					fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
174				}
175			}
176		}
177	}
178
179	fmt.Println("}")
180}
181