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