github.com/zebozhuang/go@v0.0.0-20200207033046-f8a98f6f5c5d/src/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  }