1// Copyright 2015 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
5package ssa
6
7// checkFunc checks invariants of f.
8func checkFunc(f *Func) {
9	blockMark := make([]bool, f.NumBlocks())
10	valueMark := make([]bool, f.NumValues())
11
12	for _, b := range f.Blocks {
13		if blockMark[b.ID] {
14			f.Fatalf("block %s appears twice in %s!", b, f.Name)
15		}
16		blockMark[b.ID] = true
17		if b.Func != f {
18			f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name)
19		}
20
21		for i, e := range b.Preds {
22			if se := e.b.Succs[e.i]; se.b != b || se.i != i {
23				f.Fatalf("block pred/succ not crosslinked correctly %d:%s %d:%s", i, b, se.i, se.b)
24			}
25		}
26		for i, e := range b.Succs {
27			if pe := e.b.Preds[e.i]; pe.b != b || pe.i != i {
28				f.Fatalf("block succ/pred not crosslinked correctly %d:%s %d:%s", i, b, pe.i, pe.b)
29			}
30		}
31
32		switch b.Kind {
33		case BlockExit:
34			if len(b.Succs) != 0 {
35				f.Fatalf("exit block %s has successors", b)
36			}
37			if b.Control == nil {
38				f.Fatalf("exit block %s has no control value", b)
39			}
40			if !b.Control.Type.IsMemory() {
41				f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
42			}
43		case BlockRet:
44			if len(b.Succs) != 0 {
45				f.Fatalf("ret block %s has successors", b)
46			}
47			if b.Control == nil {
48				f.Fatalf("ret block %s has nil control", b)
49			}
50			if !b.Control.Type.IsMemory() {
51				f.Fatalf("ret block %s has non-memory control value %s", b, b.Control.LongString())
52			}
53		case BlockRetJmp:
54			if len(b.Succs) != 0 {
55				f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
56			}
57			if b.Control == nil {
58				f.Fatalf("retjmp block %s has nil control", b)
59			}
60			if !b.Control.Type.IsMemory() {
61				f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString())
62			}
63			if b.Aux == nil {
64				f.Fatalf("retjmp block %s has nil Aux field", b)
65			}
66		case BlockPlain:
67			if len(b.Succs) != 1 {
68				f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
69			}
70			if b.Control != nil {
71				f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString())
72			}
73		case BlockIf:
74			if len(b.Succs) != 2 {
75				f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
76			}
77			if b.Control == nil {
78				f.Fatalf("if block %s has no control value", b)
79			}
80			if !b.Control.Type.IsBoolean() {
81				f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
82			}
83		case BlockDefer:
84			if len(b.Succs) != 2 {
85				f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
86			}
87			if b.Control == nil {
88				f.Fatalf("defer block %s has no control value", b)
89			}
90			if !b.Control.Type.IsMemory() {
91				f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString())
92			}
93		case BlockFirst:
94			if len(b.Succs) != 2 {
95				f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
96			}
97			if b.Control != nil {
98				f.Fatalf("plain/dead block %s has a control value", b)
99			}
100		}
101		if len(b.Succs) > 2 && b.Likely != BranchUnknown {
102			f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
103		}
104
105		for _, v := range b.Values {
106			// Check to make sure argument count makes sense (argLen of -1 indicates
107			// variable length args)
108			nArgs := opcodeTable[v.Op].argLen
109			if nArgs != -1 && int32(len(v.Args)) != nArgs {
110				f.Fatalf("value %s has %d args, expected %d", v.LongString(),
111					len(v.Args), nArgs)
112			}
113
114			// Check to make sure aux values make sense.
115			canHaveAux := false
116			canHaveAuxInt := false
117			switch opcodeTable[v.Op].auxType {
118			case auxNone:
119			case auxBool:
120				if v.AuxInt < 0 || v.AuxInt > 1 {
121					f.Fatalf("bad bool AuxInt value for %v", v)
122				}
123				canHaveAuxInt = true
124			case auxInt8:
125				if v.AuxInt != int64(int8(v.AuxInt)) {
126					f.Fatalf("bad int8 AuxInt value for %v", v)
127				}
128				canHaveAuxInt = true
129			case auxInt16:
130				if v.AuxInt != int64(int16(v.AuxInt)) {
131					f.Fatalf("bad int16 AuxInt value for %v", v)
132				}
133				canHaveAuxInt = true
134			case auxInt32:
135				if v.AuxInt != int64(int32(v.AuxInt)) {
136					f.Fatalf("bad int32 AuxInt value for %v", v)
137				}
138				canHaveAuxInt = true
139			case auxInt64, auxFloat64:
140				canHaveAuxInt = true
141			case auxInt128:
142				// AuxInt must be zero, so leave canHaveAuxInt set to false.
143			case auxFloat32:
144				canHaveAuxInt = true
145				if !isExactFloat32(v) {
146					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
147				}
148			case auxString, auxSym, auxTyp:
149				canHaveAux = true
150			case auxSymOff, auxSymValAndOff, auxTypSize:
151				canHaveAuxInt = true
152				canHaveAux = true
153			case auxSymInt32:
154				if v.AuxInt != int64(int32(v.AuxInt)) {
155					f.Fatalf("bad int32 AuxInt value for %v", v)
156				}
157				canHaveAuxInt = true
158				canHaveAux = true
159			default:
160				f.Fatalf("unknown aux type for %s", v.Op)
161			}
162			if !canHaveAux && v.Aux != nil {
163				f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
164			}
165			if !canHaveAuxInt && v.AuxInt != 0 {
166				f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
167			}
168
169			for i, arg := range v.Args {
170				if arg == nil {
171					f.Fatalf("value %s has nil arg", v.LongString())
172				}
173				if v.Op != OpPhi {
174					// For non-Phi ops, memory args must be last, if present
175					if arg.Type.IsMemory() && i != len(v.Args)-1 {
176						f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1)
177					}
178				}
179			}
180
181			if valueMark[v.ID] {
182				f.Fatalf("value %s appears twice!", v.LongString())
183			}
184			valueMark[v.ID] = true
185
186			if v.Block != b {
187				f.Fatalf("%s.block != %s", v, b)
188			}
189			if v.Op == OpPhi && len(v.Args) != len(b.Preds) {
190				f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b)
191			}
192
193			if v.Op == OpAddr {
194				if len(v.Args) == 0 {
195					f.Fatalf("no args for OpAddr %s", v.LongString())
196				}
197				if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB {
198					f.Fatalf("bad arg to OpAddr %v", v)
199				}
200			}
201
202			// TODO: check for cycles in values
203			// TODO: check type
204		}
205	}
206
207	// Check to make sure all Blocks referenced are in the function.
208	if !blockMark[f.Entry.ID] {
209		f.Fatalf("entry block %v is missing", f.Entry)
210	}
211	for _, b := range f.Blocks {
212		for _, c := range b.Preds {
213			if !blockMark[c.b.ID] {
214				f.Fatalf("predecessor block %v for %v is missing", c, b)
215			}
216		}
217		for _, c := range b.Succs {
218			if !blockMark[c.b.ID] {
219				f.Fatalf("successor block %v for %v is missing", c, b)
220			}
221		}
222	}
223
224	if len(f.Entry.Preds) > 0 {
225		f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds)
226	}
227
228	// Check to make sure all Values referenced are in the function.
229	for _, b := range f.Blocks {
230		for _, v := range b.Values {
231			for i, a := range v.Args {
232				if !valueMark[a.ID] {
233					f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
234				}
235			}
236		}
237		if b.Control != nil && !valueMark[b.Control.ID] {
238			f.Fatalf("control value for %s is missing: %v", b, b.Control)
239		}
240	}
241	for b := f.freeBlocks; b != nil; b = b.succstorage[0].b {
242		if blockMark[b.ID] {
243			f.Fatalf("used block b%d in free list", b.ID)
244		}
245	}
246	for v := f.freeValues; v != nil; v = v.argstorage[0] {
247		if valueMark[v.ID] {
248			f.Fatalf("used value v%d in free list", v.ID)
249		}
250	}
251
252	// Check to make sure all args dominate uses.
253	if f.RegAlloc == nil {
254		// Note: regalloc introduces non-dominating args.
255		// See TODO in regalloc.go.
256		sdom := f.sdom()
257		for _, b := range f.Blocks {
258			for _, v := range b.Values {
259				for i, arg := range v.Args {
260					x := arg.Block
261					y := b
262					if v.Op == OpPhi {
263						y = b.Preds[i].b
264					}
265					if !domCheck(f, sdom, x, y) {
266						f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString())
267					}
268				}
269			}
270			if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) {
271				f.Fatalf("control value %s for %s doesn't dominate", b.Control, b)
272			}
273		}
274	}
275
276	// Check loop construction
277	if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
278		ln := f.loopnest()
279		po := f.postorder() // use po to avoid unreachable blocks.
280		for _, b := range po {
281			for _, s := range b.Succs {
282				bb := s.Block()
283				if ln.b2l[b.ID] == nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header {
284					f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String())
285				}
286				if ln.b2l[b.ID] != nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header && !ln.b2l[b.ID].isWithinOrEq(ln.b2l[bb.ID]) {
287					f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String())
288				}
289			}
290		}
291	}
292
293	// Check use counts
294	uses := make([]int32, f.NumValues())
295	for _, b := range f.Blocks {
296		for _, v := range b.Values {
297			for _, a := range v.Args {
298				uses[a.ID]++
299			}
300		}
301		if b.Control != nil {
302			uses[b.Control.ID]++
303		}
304	}
305	for _, b := range f.Blocks {
306		for _, v := range b.Values {
307			if v.Uses != uses[v.ID] {
308				f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
309			}
310		}
311	}
312
313	memCheck(f)
314}
315
316func memCheck(f *Func) {
317	// Check that if a tuple has a memory type, it is second.
318	for _, b := range f.Blocks {
319		for _, v := range b.Values {
320			if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
321				f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
322			}
323		}
324	}
325
326	// Single live memory checks.
327	// These checks only work if there are no memory copies.
328	// (Memory copies introduce ambiguity about which mem value is really live.
329	// probably fixable, but it's easier to avoid the problem.)
330	// For the same reason, disable this check if some memory ops are unused.
331	for _, b := range f.Blocks {
332		for _, v := range b.Values {
333			if (v.Op == OpCopy || v.Uses == 0) && v.Type.IsMemory() {
334				return
335			}
336		}
337		if b != f.Entry && len(b.Preds) == 0 {
338			return
339		}
340	}
341
342	// Compute live memory at the end of each block.
343	lastmem := make([]*Value, f.NumBlocks())
344	ss := newSparseSet(f.NumValues())
345	for _, b := range f.Blocks {
346		// Mark overwritten memory values. Those are args of other
347		// ops that generate memory values.
348		ss.clear()
349		for _, v := range b.Values {
350			if v.Op == OpPhi || !v.Type.IsMemory() {
351				continue
352			}
353			if m := v.MemoryArg(); m != nil {
354				ss.add(m.ID)
355			}
356		}
357		// There should be at most one remaining unoverwritten memory value.
358		for _, v := range b.Values {
359			if !v.Type.IsMemory() {
360				continue
361			}
362			if ss.contains(v.ID) {
363				continue
364			}
365			if lastmem[b.ID] != nil {
366				f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v)
367			}
368			lastmem[b.ID] = v
369		}
370		// If there is no remaining memory value, that means there was no memory update.
371		// Take any memory arg.
372		if lastmem[b.ID] == nil {
373			for _, v := range b.Values {
374				if v.Op == OpPhi {
375					continue
376				}
377				m := v.MemoryArg()
378				if m == nil {
379					continue
380				}
381				if lastmem[b.ID] != nil && lastmem[b.ID] != m {
382					f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m)
383				}
384				lastmem[b.ID] = m
385			}
386		}
387	}
388	// Propagate last live memory through storeless blocks.
389	for {
390		changed := false
391		for _, b := range f.Blocks {
392			if lastmem[b.ID] != nil {
393				continue
394			}
395			for _, e := range b.Preds {
396				p := e.b
397				if lastmem[p.ID] != nil {
398					lastmem[b.ID] = lastmem[p.ID]
399					changed = true
400					break
401				}
402			}
403		}
404		if !changed {
405			break
406		}
407	}
408	// Check merge points.
409	for _, b := range f.Blocks {
410		for _, v := range b.Values {
411			if v.Op == OpPhi && v.Type.IsMemory() {
412				for i, a := range v.Args {
413					if a != lastmem[b.Preds[i].b.ID] {
414						f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].b.ID])
415					}
416				}
417			}
418		}
419	}
420
421	// Check that only one memory is live at any point.
422	if f.scheduled {
423		for _, b := range f.Blocks {
424			var mem *Value // the current live memory in the block
425			for _, v := range b.Values {
426				if v.Op == OpPhi {
427					if v.Type.IsMemory() {
428						mem = v
429					}
430					continue
431				}
432				if mem == nil && len(b.Preds) > 0 {
433					// If no mem phi, take mem of any predecessor.
434					mem = lastmem[b.Preds[0].b.ID]
435				}
436				for _, a := range v.Args {
437					if a.Type.IsMemory() && a != mem {
438						f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
439					}
440				}
441				if v.Type.IsMemory() {
442					mem = v
443				}
444			}
445		}
446	}
447
448	// Check that after scheduling, phis are always first in the block.
449	if f.scheduled {
450		for _, b := range f.Blocks {
451			seenNonPhi := false
452			for _, v := range b.Values {
453				if v.Op == OpPhi {
454					if seenNonPhi {
455						f.Fatalf("phi after non-phi @ %s: %s", b, v)
456					}
457				} else {
458					seenNonPhi = true
459				}
460			}
461		}
462	}
463}
464
465// domCheck reports whether x dominates y (including x==y).
466func domCheck(f *Func, sdom SparseTree, x, y *Block) bool {
467	if !sdom.isAncestorEq(f.Entry, y) {
468		// unreachable - ignore
469		return true
470	}
471	return sdom.isAncestorEq(x, y)
472}
473
474// isExactFloat32 reoprts whether v has an AuxInt that can be exactly represented as a float32.
475func isExactFloat32(v *Value) bool {
476	return v.AuxFloat() == float64(float32(v.AuxFloat()))
477}
478