// 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 //go: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("}") }