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