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