1// $G $D/$F.go && $L $F.$A &&
2// ./$A.out >tmp.go && $G tmp.go && $L -o $A.out1 tmp.$A && ./$A.out1
3// rm -f tmp.go $A.out1
4
5// NOTE: This test is not run by 'run.go' and so not run by all.bash.
6// To run this test you must use the ./run shell script.
7
8// Copyright 2012 The Go Authors.  All rights reserved.
9// Use of this source code is governed by a BSD-style
10// license that can be found in the LICENSE file.
11
12// Generate test of shift and rotate by constants.
13// The output is compiled and run.
14//
15// The output takes around a gigabyte of memory to compile, link, and run
16// but it is only done during ./run, not in normal builds using run.go.
17
18package main
19
20import (
21	"bufio"
22	"flag"
23	"fmt"
24	"os"
25	"strings"
26)
27
28func main() {
29	flag.Parse()
30
31	b := bufio.NewWriter(os.Stdout)
32	defer b.Flush()
33
34	fmt.Fprintf(b, "%s\n", prolog)
35
36	for logBits := uint(3); logBits <= 6; logBits++ {
37		typ := fmt.Sprintf("int%d", 1<<logBits)
38		fmt.Fprint(b, strings.Replace(checkFunc, "XXX", typ, -1))
39		fmt.Fprint(b, strings.Replace(checkFunc, "XXX", "u"+typ, -1))
40		for mode := 0; mode < 1<<2; mode++ {
41			gentest(b, 1<<logBits, mode&1 != 0, mode&2 != 0)
42		}
43	}
44}
45
46const prolog = `
47
48package main
49
50import (
51	"fmt"
52	"os"
53)
54
55var (
56	i8 int8 = 0x12
57	i16 int16 = 0x1234
58	i32 int32 = 0x12345678
59	i64 int64 = 0x123456789abcdef0
60	ui8 uint8 = 0x12
61	ui16 uint16 = 0x1234
62	ui32 uint32 = 0x12345678
63	ui64 uint64 = 0x123456789abcdef0
64
65	ni8 = ^i8
66	ni16 = ^i16
67	ni32 = ^i32
68	ni64 = ^i64
69	nui8 = ^ui8
70	nui16 = ^ui16
71	nui32 = ^ui32
72	nui64 = ^ui64
73)
74
75var nfail = 0
76
77func main() {
78	if nfail > 0 {
79		fmt.Printf("BUG\n")
80	}
81}
82
83`
84
85const checkFunc = `
86func check_XXX(desc string, have, want XXX) {
87	if have != want {
88		nfail++
89		fmt.Printf("%s = %T(%#x), want %T(%#x)\n", desc, have, have, want, want)
90		if nfail >= 100 {
91			fmt.Printf("BUG: stopping after 100 failures\n")
92			os.Exit(0)
93		}
94	}
95}
96`
97
98var (
99	uop = [2]func(x, y uint64) uint64{
100		func(x, y uint64) uint64 {
101			return x | y
102		},
103		func(x, y uint64) uint64 {
104			return x ^ y
105		},
106	}
107	iop = [2]func(x, y int64) int64{
108		func(x, y int64) int64 {
109			return x | y
110		},
111		func(x, y int64) int64 {
112			return x ^ y
113		},
114	}
115	cop = [2]byte{'|', '^'}
116)
117
118func gentest(b *bufio.Writer, bits uint, unsigned, inverted bool) {
119	fmt.Fprintf(b, "func init() {\n")
120	defer fmt.Fprintf(b, "}\n")
121	n := 0
122
123	// Generate tests for left/right and right/left.
124	for l := uint(0); l <= bits; l++ {
125		for r := uint(0); r <= bits; r++ {
126			for o, op := range cop {
127				typ := fmt.Sprintf("int%d", bits)
128				v := fmt.Sprintf("i%d", bits)
129				if unsigned {
130					typ = "u" + typ
131					v = "u" + v
132				}
133				v0 := int64(0x123456789abcdef0)
134				if inverted {
135					v = "n" + v
136					v0 = ^v0
137				}
138				expr1 := fmt.Sprintf("%s<<%d %c %s>>%d", v, l, op, v, r)
139				expr2 := fmt.Sprintf("%s>>%d %c %s<<%d", v, r, op, v, l)
140
141				var result string
142				if unsigned {
143					v := uint64(v0) >> (64 - bits)
144					v = uop[o](v<<l, v>>r)
145					v <<= 64 - bits
146					v >>= 64 - bits
147					result = fmt.Sprintf("%#x", v)
148				} else {
149					v := int64(v0) >> (64 - bits)
150					v = iop[o](v<<l, v>>r)
151					v <<= 64 - bits
152					v >>= 64 - bits
153					result = fmt.Sprintf("%#x", v)
154				}
155
156				fmt.Fprintf(b, "\tcheck_%s(%q, %s, %s(%s))\n", typ, expr1, expr1, typ, result)
157				fmt.Fprintf(b, "\tcheck_%s(%q, %s, %s(%s))\n", typ, expr2, expr2, typ, result)
158
159				// Chop test into multiple functions so that there's not one
160				// enormous function to compile/link.
161				// All the functions are named init so we don't have to do
162				// anything special to call them.  ☺
163				if n++; n >= 50 {
164					fmt.Fprintf(b, "}\n")
165					fmt.Fprintf(b, "func init() {\n")
166					n = 0
167				}
168			}
169		}
170	}
171}
172