| // runoutput |
| |
| // Copyright 2015 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // terribly slow on wasm |
| // +build !wasm |
| |
| package main |
| |
| import ( |
| "fmt" |
| "math/big" |
| "unsafe" |
| ) |
| |
| var one = big.NewInt(1) |
| |
| type _type struct { |
| name string |
| bits uint |
| signed bool |
| } |
| |
| // testvalues returns a list of all test values for this type. |
| func (t *_type) testvalues() []*big.Int { |
| var a []*big.Int |
| |
| a = append(a, big.NewInt(0)) |
| a = append(a, big.NewInt(1)) |
| a = append(a, big.NewInt(2)) |
| if t.signed { |
| a = append(a, big.NewInt(-1)) |
| a = append(a, big.NewInt(-2)) |
| r := big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(1))) |
| r = big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(2))) |
| r = big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits-1).Neg(r)) |
| r = big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits-1).Neg(r).Add(r, big.NewInt(1))) |
| } else { |
| r := big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(1))) |
| r = big.NewInt(1) |
| a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(2))) |
| } |
| return a |
| } |
| |
| // trunc truncates a value to the range of the given type. |
| func (t *_type) trunc(x *big.Int) *big.Int { |
| r := new(big.Int) |
| m := new(big.Int) |
| m.Lsh(one, t.bits) |
| m.Sub(m, one) |
| r.And(x, m) |
| if t.signed && r.Bit(int(t.bits)-1) == 1 { |
| m.Neg(one) |
| m.Lsh(m, t.bits) |
| r.Or(r, m) |
| } |
| return r |
| } |
| |
| var types = []_type{ |
| _type{"byte", 8, false}, |
| _type{"int8", 8, true}, |
| _type{"uint8", 8, false}, |
| _type{"rune", 32, true}, |
| _type{"int16", 16, true}, |
| _type{"uint16", 16, false}, |
| _type{"int32", 32, true}, |
| _type{"uint32", 32, false}, |
| _type{"int64", 64, true}, |
| _type{"uint64", 64, false}, |
| _type{"int", 8 * uint(unsafe.Sizeof(int(0))), true}, |
| _type{"uint", 8 * uint(unsafe.Sizeof(uint(0))), false}, |
| _type{"uintptr", 8 * uint(unsafe.Sizeof((*byte)(nil))), false}, |
| } |
| |
| type binop struct { |
| name string |
| eval func(x, y *big.Int) *big.Int |
| } |
| |
| var binops = []binop{ |
| binop{"+", func(x, y *big.Int) *big.Int { return new(big.Int).Add(x, y) }}, |
| binop{"-", func(x, y *big.Int) *big.Int { return new(big.Int).Sub(x, y) }}, |
| binop{"*", func(x, y *big.Int) *big.Int { return new(big.Int).Mul(x, y) }}, |
| binop{"/", func(x, y *big.Int) *big.Int { return new(big.Int).Quo(x, y) }}, |
| binop{"%", func(x, y *big.Int) *big.Int { return new(big.Int).Rem(x, y) }}, |
| binop{"&", func(x, y *big.Int) *big.Int { return new(big.Int).And(x, y) }}, |
| binop{"|", func(x, y *big.Int) *big.Int { return new(big.Int).Or(x, y) }}, |
| binop{"^", func(x, y *big.Int) *big.Int { return new(big.Int).Xor(x, y) }}, |
| binop{"&^", func(x, y *big.Int) *big.Int { return new(big.Int).AndNot(x, y) }}, |
| } |
| |
| type unop struct { |
| name string |
| eval func(x *big.Int) *big.Int |
| } |
| |
| var unops = []unop{ |
| unop{"+", func(x *big.Int) *big.Int { return new(big.Int).Set(x) }}, |
| unop{"-", func(x *big.Int) *big.Int { return new(big.Int).Neg(x) }}, |
| unop{"^", func(x *big.Int) *big.Int { return new(big.Int).Not(x) }}, |
| } |
| |
| type shiftop struct { |
| name string |
| eval func(x *big.Int, i uint) *big.Int |
| } |
| |
| var shiftops = []shiftop{ |
| shiftop{"<<", func(x *big.Int, i uint) *big.Int { return new(big.Int).Lsh(x, i) }}, |
| shiftop{">>", func(x *big.Int, i uint) *big.Int { return new(big.Int).Rsh(x, i) }}, |
| } |
| |
| // valname returns the name of n as can be used as part of a variable name. |
| func valname(n *big.Int) string { |
| s := fmt.Sprintf("%d", n) |
| if s[0] == '-' { |
| s = "neg" + s[1:] |
| } |
| return s |
| } |
| |
| func main() { |
| fmt.Println("package main") |
| |
| // We make variables to hold all the different values we'd like to use. |
| // We use global variables to prevent any constant folding. |
| for _, t := range types { |
| for _, n := range t.testvalues() { |
| fmt.Printf("var %s_%s %s = %d\n", t.name, valname(n), t.name, n) |
| } |
| } |
| |
| fmt.Println("func main() {") |
| |
| for _, t := range types { |
| // test binary ops |
| for _, op := range binops { |
| for _, x := range t.testvalues() { |
| for _, y := range t.testvalues() { |
| if (op.name == "/" || op.name == "%") && y.Sign() == 0 { |
| continue |
| } |
| r := t.trunc(op.eval(x, y)) |
| eqn := fmt.Sprintf("%s_%s %s %s_%s != %d", t.name, valname(x), op.name, t.name, valname(y), r) |
| fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn) |
| } |
| } |
| } |
| // test unary ops |
| for _, op := range unops { |
| for _, x := range t.testvalues() { |
| r := t.trunc(op.eval(x)) |
| eqn := fmt.Sprintf("%s %s_%s != %d", op.name, t.name, valname(x), r) |
| fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn) |
| } |
| } |
| // test shifts |
| for _, op := range shiftops { |
| for _, x := range t.testvalues() { |
| |
| for _, i := range []uint{0, 1, t.bits - 2, t.bits - 1, t.bits, t.bits + 1} { |
| r := t.trunc(op.eval(x, i)) |
| eqn := fmt.Sprintf("%s_%s %s %d != %d", t.name, valname(x), op.name, i, r) |
| fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn) |
| } |
| } |
| } |
| } |
| |
| fmt.Println("}") |
| } |