github.com/ltltlt/go-source-code@v0.0.0-20190830023027-95be009773aa/cmd/compile/internal/gc/testdata/gen/cmpConstGen.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This program generates a test to verify that the standard comparison 6 // operators properly handle one const operand. The test file should be 7 // generated with a known working version of go. 8 // launch with `go run cmpConstGen.go` a file called cmpConst.go 9 // will be written into the parent directory containing the tests 10 11 package main 12 13 import ( 14 "bytes" 15 "fmt" 16 "go/format" 17 "io/ioutil" 18 "log" 19 "math/big" 20 "sort" 21 ) 22 23 const ( 24 maxU64 = (1 << 64) - 1 25 maxU32 = (1 << 32) - 1 26 maxU16 = (1 << 16) - 1 27 maxU8 = (1 << 8) - 1 28 29 maxI64 = (1 << 63) - 1 30 maxI32 = (1 << 31) - 1 31 maxI16 = (1 << 15) - 1 32 maxI8 = (1 << 7) - 1 33 34 minI64 = -(1 << 63) 35 minI32 = -(1 << 31) 36 minI16 = -(1 << 15) 37 minI8 = -(1 << 7) 38 ) 39 40 func cmp(left *big.Int, op string, right *big.Int) bool { 41 switch left.Cmp(right) { 42 case -1: // less than 43 return op == "<" || op == "<=" || op == "!=" 44 case 0: // equal 45 return op == "==" || op == "<=" || op == ">=" 46 case 1: // greater than 47 return op == ">" || op == ">=" || op == "!=" 48 } 49 panic("unexpected comparison value") 50 } 51 52 func inRange(typ string, val *big.Int) bool { 53 min, max := &big.Int{}, &big.Int{} 54 switch typ { 55 case "uint64": 56 max = max.SetUint64(maxU64) 57 case "uint32": 58 max = max.SetUint64(maxU32) 59 case "uint16": 60 max = max.SetUint64(maxU16) 61 case "uint8": 62 max = max.SetUint64(maxU8) 63 case "int64": 64 min = min.SetInt64(minI64) 65 max = max.SetInt64(maxI64) 66 case "int32": 67 min = min.SetInt64(minI32) 68 max = max.SetInt64(maxI32) 69 case "int16": 70 min = min.SetInt64(minI16) 71 max = max.SetInt64(maxI16) 72 case "int8": 73 min = min.SetInt64(minI8) 74 max = max.SetInt64(maxI8) 75 default: 76 panic("unexpected type") 77 } 78 return cmp(min, "<=", val) && cmp(val, "<=", max) 79 } 80 81 func getValues(typ string) []*big.Int { 82 Uint := func(v uint64) *big.Int { return big.NewInt(0).SetUint64(v) } 83 Int := func(v int64) *big.Int { return big.NewInt(0).SetInt64(v) } 84 values := []*big.Int{ 85 // limits 86 Uint(maxU64), 87 Uint(maxU64 - 1), 88 Uint(maxI64 + 1), 89 Uint(maxI64), 90 Uint(maxI64 - 1), 91 Uint(maxU32 + 1), 92 Uint(maxU32), 93 Uint(maxU32 - 1), 94 Uint(maxI32 + 1), 95 Uint(maxI32), 96 Uint(maxI32 - 1), 97 Uint(maxU16 + 1), 98 Uint(maxU16), 99 Uint(maxU16 - 1), 100 Uint(maxI16 + 1), 101 Uint(maxI16), 102 Uint(maxI16 - 1), 103 Uint(maxU8 + 1), 104 Uint(maxU8), 105 Uint(maxU8 - 1), 106 Uint(maxI8 + 1), 107 Uint(maxI8), 108 Uint(maxI8 - 1), 109 Uint(0), 110 Int(minI8 + 1), 111 Int(minI8), 112 Int(minI8 - 1), 113 Int(minI16 + 1), 114 Int(minI16), 115 Int(minI16 - 1), 116 Int(minI32 + 1), 117 Int(minI32), 118 Int(minI32 - 1), 119 Int(minI64 + 1), 120 Int(minI64), 121 122 // other possibly interesting values 123 Uint(1), 124 Int(-1), 125 Uint(0xff << 56), 126 Uint(0xff << 32), 127 Uint(0xff << 24), 128 } 129 sort.Slice(values, func(i, j int) bool { return values[i].Cmp(values[j]) == -1 }) 130 var ret []*big.Int 131 for _, val := range values { 132 if !inRange(typ, val) { 133 continue 134 } 135 ret = append(ret, val) 136 } 137 return ret 138 } 139 140 func sigString(v *big.Int) string { 141 var t big.Int 142 t.Abs(v) 143 if v.Sign() == -1 { 144 return "neg" + t.String() 145 } 146 return t.String() 147 } 148 149 func main() { 150 types := []string{ 151 "uint64", "uint32", "uint16", "uint8", 152 "int64", "int32", "int16", "int8", 153 } 154 155 w := new(bytes.Buffer) 156 fmt.Fprintf(w, "// run\n") 157 fmt.Fprintf(w, "// Code generated by gen/cmpConstGen.go. DO NOT EDIT.\n\n") 158 fmt.Fprintf(w, "package main;\n") 159 fmt.Fprintf(w, "import (\"fmt\"; \"reflect\"; \"runtime\";)\n") 160 fmt.Fprintf(w, "// results show the expected result for the elements left of, equal to and right of the index.\n") 161 fmt.Fprintf(w, "type result struct{l, e, r bool}\n") 162 fmt.Fprintf(w, "var (\n") 163 fmt.Fprintf(w, " eq = result{l: false, e: true, r: false}\n") 164 fmt.Fprintf(w, " ne = result{l: true, e: false, r: true}\n") 165 fmt.Fprintf(w, " lt = result{l: true, e: false, r: false}\n") 166 fmt.Fprintf(w, " le = result{l: true, e: true, r: false}\n") 167 fmt.Fprintf(w, " gt = result{l: false, e: false, r: true}\n") 168 fmt.Fprintf(w, " ge = result{l: false, e: true, r: true}\n") 169 fmt.Fprintf(w, ")\n") 170 171 operators := []struct{ op, name string }{ 172 {"<", "lt"}, 173 {"<=", "le"}, 174 {">", "gt"}, 175 {">=", "ge"}, 176 {"==", "eq"}, 177 {"!=", "ne"}, 178 } 179 180 for _, typ := range types { 181 // generate a slice containing valid values for this type 182 fmt.Fprintf(w, "\n// %v tests\n", typ) 183 values := getValues(typ) 184 fmt.Fprintf(w, "var %v_vals = []%v{\n", typ, typ) 185 for _, val := range values { 186 fmt.Fprintf(w, "%v,\n", val.String()) 187 } 188 fmt.Fprintf(w, "}\n") 189 190 // generate test functions 191 for _, r := range values { 192 // TODO: could also test constant on lhs. 193 sig := sigString(r) 194 for _, op := range operators { 195 // no need for go:noinline because the function is called indirectly 196 fmt.Fprintf(w, "func %v_%v_%v(x %v) bool { return x %v %v; }\n", op.name, sig, typ, typ, op.op, r.String()) 197 } 198 } 199 200 // generate a table of test cases 201 fmt.Fprintf(w, "var %v_tests = []struct{\n", typ) 202 fmt.Fprintf(w, " idx int // index of the constant used\n") 203 fmt.Fprintf(w, " exp result // expected results\n") 204 fmt.Fprintf(w, " fn func(%v) bool\n", typ) 205 fmt.Fprintf(w, "}{\n") 206 for i, r := range values { 207 sig := sigString(r) 208 for _, op := range operators { 209 fmt.Fprintf(w, "{idx: %v,", i) 210 fmt.Fprintf(w, "exp: %v,", op.name) 211 fmt.Fprintf(w, "fn: %v_%v_%v},\n", op.name, sig, typ) 212 } 213 } 214 fmt.Fprintf(w, "}\n") 215 } 216 217 // emit the main function, looping over all test cases 218 fmt.Fprintf(w, "func main() {\n") 219 for _, typ := range types { 220 fmt.Fprintf(w, "for i, test := range %v_tests {\n", typ) 221 fmt.Fprintf(w, " for j, x := range %v_vals {\n", typ) 222 fmt.Fprintf(w, " want := test.exp.l\n") 223 fmt.Fprintf(w, " if j == test.idx {\nwant = test.exp.e\n}") 224 fmt.Fprintf(w, " else if j > test.idx {\nwant = test.exp.r\n}\n") 225 fmt.Fprintf(w, " if test.fn(x) != want {\n") 226 fmt.Fprintf(w, " fn := runtime.FuncForPC(reflect.ValueOf(test.fn).Pointer()).Name()\n") 227 fmt.Fprintf(w, " msg := fmt.Sprintf(\"test failed: %%v(%%v) != %%v [type=%v i=%%v j=%%v idx=%%v]\", fn, x, want, i, j, test.idx)\n", typ) 228 fmt.Fprintf(w, " panic(msg)\n") 229 fmt.Fprintf(w, " }\n") 230 fmt.Fprintf(w, " }\n") 231 fmt.Fprintf(w, "}\n") 232 } 233 fmt.Fprintf(w, "}\n") 234 235 // gofmt result 236 b := w.Bytes() 237 src, err := format.Source(b) 238 if err != nil { 239 fmt.Printf("%s\n", b) 240 panic(err) 241 } 242 243 // write to file 244 err = ioutil.WriteFile("../cmpConst.go", src, 0666) 245 if err != nil { 246 log.Fatalf("can't write output: %v\n", err) 247 } 248 }