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
7import (
8	"cmd/compile/internal/ir"
9	"cmd/internal/obj/s390x"
10	"math"
11	"math/bits"
12)
13
14// checkFunc checks invariants of f.
15func checkFunc(f *Func) {
16	blockMark := make([]bool, f.NumBlocks())
17	valueMark := make([]bool, f.NumValues())
18
19	for _, b := range f.Blocks {
20		if blockMark[b.ID] {
21			f.Fatalf("block %s appears twice in %s!", b, f.Name)
22		}
23		blockMark[b.ID] = true
24		if b.Func != f {
25			f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name)
26		}
27
28		for i, e := range b.Preds {
29			if se := e.b.Succs[e.i]; se.b != b || se.i != i {
30				f.Fatalf("block pred/succ not crosslinked correctly %d:%s %d:%s", i, b, se.i, se.b)
31			}
32		}
33		for i, e := range b.Succs {
34			if pe := e.b.Preds[e.i]; pe.b != b || pe.i != i {
35				f.Fatalf("block succ/pred not crosslinked correctly %d:%s %d:%s", i, b, pe.i, pe.b)
36			}
37		}
38
39		switch b.Kind {
40		case BlockExit:
41			if len(b.Succs) != 0 {
42				f.Fatalf("exit block %s has successors", b)
43			}
44			if b.NumControls() != 1 {
45				f.Fatalf("exit block %s has no control value", b)
46			}
47			if !b.Controls[0].Type.IsMemory() {
48				f.Fatalf("exit block %s has non-memory control value %s", b, b.Controls[0].LongString())
49			}
50		case BlockRet:
51			if len(b.Succs) != 0 {
52				f.Fatalf("ret block %s has successors", b)
53			}
54			if b.NumControls() != 1 {
55				f.Fatalf("ret block %s has nil control", b)
56			}
57			if !b.Controls[0].Type.IsMemory() {
58				f.Fatalf("ret block %s has non-memory control value %s", b, b.Controls[0].LongString())
59			}
60		case BlockRetJmp:
61			if len(b.Succs) != 0 {
62				f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
63			}
64			if b.NumControls() != 1 {
65				f.Fatalf("retjmp block %s has nil control", b)
66			}
67			if !b.Controls[0].Type.IsMemory() {
68				f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Controls[0].LongString())
69			}
70		case BlockPlain:
71			if len(b.Succs) != 1 {
72				f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
73			}
74			if b.NumControls() != 0 {
75				f.Fatalf("plain block %s has non-nil control %s", b, b.Controls[0].LongString())
76			}
77		case BlockIf:
78			if len(b.Succs) != 2 {
79				f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
80			}
81			if b.NumControls() != 1 {
82				f.Fatalf("if block %s has no control value", b)
83			}
84			if !b.Controls[0].Type.IsBoolean() {
85				f.Fatalf("if block %s has non-bool control value %s", b, b.Controls[0].LongString())
86			}
87		case BlockDefer:
88			if len(b.Succs) != 2 {
89				f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
90			}
91			if b.NumControls() != 1 {
92				f.Fatalf("defer block %s has no control value", b)
93			}
94			if !b.Controls[0].Type.IsMemory() {
95				f.Fatalf("defer block %s has non-memory control value %s", b, b.Controls[0].LongString())
96			}
97		case BlockFirst:
98			if len(b.Succs) != 2 {
99				f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
100			}
101			if b.NumControls() != 0 {
102				f.Fatalf("plain/dead block %s has a control value", b)
103			}
104		case BlockJumpTable:
105			if b.NumControls() != 1 {
106				f.Fatalf("jumpTable block %s has no control value", b)
107			}
108		}
109		if len(b.Succs) != 2 && b.Likely != BranchUnknown {
110			f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
111		}
112
113		for _, v := range b.Values {
114			// Check to make sure argument count makes sense (argLen of -1 indicates
115			// variable length args)
116			nArgs := opcodeTable[v.Op].argLen
117			if nArgs != -1 && int32(len(v.Args)) != nArgs {
118				f.Fatalf("value %s has %d args, expected %d", v.LongString(),
119					len(v.Args), nArgs)
120			}
121
122			// Check to make sure aux values make sense.
123			canHaveAux := false
124			canHaveAuxInt := false
125			// TODO: enforce types of Aux in this switch (like auxString does below)
126			switch opcodeTable[v.Op].auxType {
127			case auxNone:
128			case auxBool:
129				if v.AuxInt < 0 || v.AuxInt > 1 {
130					f.Fatalf("bad bool AuxInt value for %v", v)
131				}
132				canHaveAuxInt = true
133			case auxInt8:
134				if v.AuxInt != int64(int8(v.AuxInt)) {
135					f.Fatalf("bad int8 AuxInt value for %v", v)
136				}
137				canHaveAuxInt = true
138			case auxInt16:
139				if v.AuxInt != int64(int16(v.AuxInt)) {
140					f.Fatalf("bad int16 AuxInt value for %v", v)
141				}
142				canHaveAuxInt = true
143			case auxInt32:
144				if v.AuxInt != int64(int32(v.AuxInt)) {
145					f.Fatalf("bad int32 AuxInt value for %v", v)
146				}
147				canHaveAuxInt = true
148			case auxInt64, auxARM64BitField:
149				canHaveAuxInt = true
150			case auxInt128:
151				// AuxInt must be zero, so leave canHaveAuxInt set to false.
152			case auxUInt8:
153				if v.AuxInt != int64(uint8(v.AuxInt)) {
154					f.Fatalf("bad uint8 AuxInt value for %v", v)
155				}
156				canHaveAuxInt = true
157			case auxFloat32:
158				canHaveAuxInt = true
159				if math.IsNaN(v.AuxFloat()) {
160					f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
161				}
162				if !isExactFloat32(v.AuxFloat()) {
163					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
164				}
165			case auxFloat64:
166				canHaveAuxInt = true
167				if math.IsNaN(v.AuxFloat()) {
168					f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
169				}
170			case auxString:
171				if _, ok := v.Aux.(stringAux); !ok {
172					f.Fatalf("value %v has Aux type %T, want string", v, v.Aux)
173				}
174				canHaveAux = true
175			case auxCallOff:
176				canHaveAuxInt = true
177				fallthrough
178			case auxCall:
179				if ac, ok := v.Aux.(*AuxCall); ok {
180					if v.Op == OpStaticCall && ac.Fn == nil {
181						f.Fatalf("value %v has *AuxCall with nil Fn", v)
182					}
183				} else {
184					f.Fatalf("value %v has Aux type %T, want *AuxCall", v, v.Aux)
185				}
186				canHaveAux = true
187			case auxNameOffsetInt8:
188				if _, ok := v.Aux.(*AuxNameOffset); !ok {
189					f.Fatalf("value %v has Aux type %T, want *AuxNameOffset", v, v.Aux)
190				}
191				canHaveAux = true
192				canHaveAuxInt = true
193			case auxSym, auxTyp:
194				canHaveAux = true
195			case auxSymOff, auxSymValAndOff, auxTypSize:
196				canHaveAuxInt = true
197				canHaveAux = true
198			case auxCCop:
199				if opcodeTable[Op(v.AuxInt)].name == "OpInvalid" {
200					f.Fatalf("value %v has an AuxInt value that is a valid opcode", v)
201				}
202				canHaveAuxInt = true
203			case auxS390XCCMask:
204				if _, ok := v.Aux.(s390x.CCMask); !ok {
205					f.Fatalf("bad type %T for S390XCCMask in %v", v.Aux, v)
206				}
207				canHaveAux = true
208			case auxS390XRotateParams:
209				if _, ok := v.Aux.(s390x.RotateParams); !ok {
210					f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
211				}
212				canHaveAux = true
213			case auxFlagConstant:
214				if v.AuxInt < 0 || v.AuxInt > 15 {
215					f.Fatalf("bad FlagConstant AuxInt value for %v", v)
216				}
217				canHaveAuxInt = true
218			default:
219				f.Fatalf("unknown aux type for %s", v.Op)
220			}
221			if !canHaveAux && v.Aux != nil {
222				f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
223			}
224			if !canHaveAuxInt && v.AuxInt != 0 {
225				f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
226			}
227
228			for i, arg := range v.Args {
229				if arg == nil {
230					f.Fatalf("value %s has nil arg", v.LongString())
231				}
232				if v.Op != OpPhi {
233					// For non-Phi ops, memory args must be last, if present
234					if arg.Type.IsMemory() && i != len(v.Args)-1 {
235						f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1)
236					}
237				}
238			}
239
240			if valueMark[v.ID] {
241				f.Fatalf("value %s appears twice!", v.LongString())
242			}
243			valueMark[v.ID] = true
244
245			if v.Block != b {
246				f.Fatalf("%s.block != %s", v, b)
247			}
248			if v.Op == OpPhi && len(v.Args) != len(b.Preds) {
249				f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b)
250			}
251
252			if v.Op == OpAddr {
253				if len(v.Args) == 0 {
254					f.Fatalf("no args for OpAddr %s", v.LongString())
255				}
256				if v.Args[0].Op != OpSB {
257					f.Fatalf("bad arg to OpAddr %v", v)
258				}
259			}
260
261			if v.Op == OpLocalAddr {
262				if len(v.Args) != 2 {
263					f.Fatalf("wrong # of args for OpLocalAddr %s", v.LongString())
264				}
265				if v.Args[0].Op != OpSP {
266					f.Fatalf("bad arg 0 to OpLocalAddr %v", v)
267				}
268				if !v.Args[1].Type.IsMemory() {
269					f.Fatalf("bad arg 1 to OpLocalAddr %v", v)
270				}
271			}
272
273			if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() {
274				f.Fatalf("unexpected floating-point type %v", v.LongString())
275			}
276
277			// Check types.
278			// TODO: more type checks?
279			switch c := f.Config; v.Op {
280			case OpSP, OpSB:
281				if v.Type != c.Types.Uintptr {
282					f.Fatalf("bad %s type: want uintptr, have %s",
283						v.Op, v.Type.String())
284				}
285			case OpStringLen:
286				if v.Type != c.Types.Int {
287					f.Fatalf("bad %s type: want int, have %s",
288						v.Op, v.Type.String())
289				}
290			case OpLoad:
291				if !v.Args[1].Type.IsMemory() {
292					f.Fatalf("bad arg 1 type to %s: want mem, have %s",
293						v.Op, v.Args[1].Type.String())
294				}
295			case OpStore:
296				if !v.Type.IsMemory() {
297					f.Fatalf("bad %s type: want mem, have %s",
298						v.Op, v.Type.String())
299				}
300				if !v.Args[2].Type.IsMemory() {
301					f.Fatalf("bad arg 2 type to %s: want mem, have %s",
302						v.Op, v.Args[2].Type.String())
303				}
304			case OpCondSelect:
305				if !v.Args[2].Type.IsBoolean() {
306					f.Fatalf("bad arg 2 type to %s: want boolean, have %s",
307						v.Op, v.Args[2].Type.String())
308				}
309			case OpAddPtr:
310				if !v.Args[0].Type.IsPtrShaped() && v.Args[0].Type != c.Types.Uintptr {
311					f.Fatalf("bad arg 0 type to %s: want ptr, have %s", v.Op, v.Args[0].LongString())
312				}
313				if !v.Args[1].Type.IsInteger() {
314					f.Fatalf("bad arg 1 type to %s: want integer, have %s", v.Op, v.Args[1].LongString())
315				}
316			case OpVarDef:
317				n := v.Aux.(*ir.Name)
318				if !n.Type().HasPointers() && !IsMergeCandidate(n) {
319					f.Fatalf("vardef must be merge candidate or have pointer type %s", v.Aux.(*ir.Name).Type().String())
320				}
321			case OpNilCheck:
322				// nil checks have pointer type before scheduling, and
323				// void type after scheduling.
324				if f.scheduled {
325					if v.Uses != 0 {
326						f.Fatalf("nilcheck must have 0 uses %s", v.Uses)
327					}
328					if !v.Type.IsVoid() {
329						f.Fatalf("nilcheck must have void type %s", v.Type.String())
330					}
331				} else {
332					if !v.Type.IsPtrShaped() && !v.Type.IsUintptr() {
333						f.Fatalf("nilcheck must have pointer type %s", v.Type.String())
334					}
335				}
336				if !v.Args[0].Type.IsPtrShaped() && !v.Args[0].Type.IsUintptr() {
337					f.Fatalf("nilcheck must have argument of pointer type %s", v.Args[0].Type.String())
338				}
339				if !v.Args[1].Type.IsMemory() {
340					f.Fatalf("bad arg 1 type to %s: want mem, have %s",
341						v.Op, v.Args[1].Type.String())
342				}
343			}
344
345			// TODO: check for cycles in values
346		}
347	}
348
349	// Check to make sure all Blocks referenced are in the function.
350	if !blockMark[f.Entry.ID] {
351		f.Fatalf("entry block %v is missing", f.Entry)
352	}
353	for _, b := range f.Blocks {
354		for _, c := range b.Preds {
355			if !blockMark[c.b.ID] {
356				f.Fatalf("predecessor block %v for %v is missing", c, b)
357			}
358		}
359		for _, c := range b.Succs {
360			if !blockMark[c.b.ID] {
361				f.Fatalf("successor block %v for %v is missing", c, b)
362			}
363		}
364	}
365
366	if len(f.Entry.Preds) > 0 {
367		f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds)
368	}
369
370	// Check to make sure all Values referenced are in the function.
371	for _, b := range f.Blocks {
372		for _, v := range b.Values {
373			for i, a := range v.Args {
374				if !valueMark[a.ID] {
375					f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
376				}
377			}
378		}
379		for _, c := range b.ControlValues() {
380			if !valueMark[c.ID] {
381				f.Fatalf("control value for %s is missing: %v", b, c)
382			}
383		}
384	}
385	for b := f.freeBlocks; b != nil; b = b.succstorage[0].b {
386		if blockMark[b.ID] {
387			f.Fatalf("used block b%d in free list", b.ID)
388		}
389	}
390	for v := f.freeValues; v != nil; v = v.argstorage[0] {
391		if valueMark[v.ID] {
392			f.Fatalf("used value v%d in free list", v.ID)
393		}
394	}
395
396	// Check to make sure all args dominate uses.
397	if f.RegAlloc == nil {
398		// Note: regalloc introduces non-dominating args.
399		// See TODO in regalloc.go.
400		sdom := f.Sdom()
401		for _, b := range f.Blocks {
402			for _, v := range b.Values {
403				for i, arg := range v.Args {
404					x := arg.Block
405					y := b
406					if v.Op == OpPhi {
407						y = b.Preds[i].b
408					}
409					if !domCheck(f, sdom, x, y) {
410						f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString())
411					}
412				}
413			}
414			for _, c := range b.ControlValues() {
415				if !domCheck(f, sdom, c.Block, b) {
416					f.Fatalf("control value %s for %s doesn't dominate", c, b)
417				}
418			}
419		}
420	}
421
422	// Check loop construction
423	if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
424		ln := f.loopnest()
425		if !ln.hasIrreducible {
426			po := f.postorder() // use po to avoid unreachable blocks.
427			for _, b := range po {
428				for _, s := range b.Succs {
429					bb := s.Block()
430					if ln.b2l[b.ID] == nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header {
431						f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String())
432					}
433					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]) {
434						f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String())
435					}
436				}
437			}
438		}
439	}
440
441	// Check use counts
442	uses := make([]int32, f.NumValues())
443	for _, b := range f.Blocks {
444		for _, v := range b.Values {
445			for _, a := range v.Args {
446				uses[a.ID]++
447			}
448		}
449		for _, c := range b.ControlValues() {
450			uses[c.ID]++
451		}
452	}
453	for _, b := range f.Blocks {
454		for _, v := range b.Values {
455			if v.Uses != uses[v.ID] {
456				f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
457			}
458		}
459	}
460
461	memCheck(f)
462}
463
464func memCheck(f *Func) {
465	// Check that if a tuple has a memory type, it is second.
466	for _, b := range f.Blocks {
467		for _, v := range b.Values {
468			if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
469				f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
470			}
471		}
472	}
473
474	// Single live memory checks.
475	// These checks only work if there are no memory copies.
476	// (Memory copies introduce ambiguity about which mem value is really live.
477	// probably fixable, but it's easier to avoid the problem.)
478	// For the same reason, disable this check if some memory ops are unused.
479	for _, b := range f.Blocks {
480		for _, v := range b.Values {
481			if (v.Op == OpCopy || v.Uses == 0) && v.Type.IsMemory() {
482				return
483			}
484		}
485		if b != f.Entry && len(b.Preds) == 0 {
486			return
487		}
488	}
489
490	// Compute live memory at the end of each block.
491	lastmem := make([]*Value, f.NumBlocks())
492	ss := newSparseSet(f.NumValues())
493	for _, b := range f.Blocks {
494		// Mark overwritten memory values. Those are args of other
495		// ops that generate memory values.
496		ss.clear()
497		for _, v := range b.Values {
498			if v.Op == OpPhi || !v.Type.IsMemory() {
499				continue
500			}
501			if m := v.MemoryArg(); m != nil {
502				ss.add(m.ID)
503			}
504		}
505		// There should be at most one remaining unoverwritten memory value.
506		for _, v := range b.Values {
507			if !v.Type.IsMemory() {
508				continue
509			}
510			if ss.contains(v.ID) {
511				continue
512			}
513			if lastmem[b.ID] != nil {
514				f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v)
515			}
516			lastmem[b.ID] = v
517		}
518		// If there is no remaining memory value, that means there was no memory update.
519		// Take any memory arg.
520		if lastmem[b.ID] == nil {
521			for _, v := range b.Values {
522				if v.Op == OpPhi {
523					continue
524				}
525				m := v.MemoryArg()
526				if m == nil {
527					continue
528				}
529				if lastmem[b.ID] != nil && lastmem[b.ID] != m {
530					f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m)
531				}
532				lastmem[b.ID] = m
533			}
534		}
535	}
536	// Propagate last live memory through storeless blocks.
537	for {
538		changed := false
539		for _, b := range f.Blocks {
540			if lastmem[b.ID] != nil {
541				continue
542			}
543			for _, e := range b.Preds {
544				p := e.b
545				if lastmem[p.ID] != nil {
546					lastmem[b.ID] = lastmem[p.ID]
547					changed = true
548					break
549				}
550			}
551		}
552		if !changed {
553			break
554		}
555	}
556	// Check merge points.
557	for _, b := range f.Blocks {
558		for _, v := range b.Values {
559			if v.Op == OpPhi && v.Type.IsMemory() {
560				for i, a := range v.Args {
561					if a != lastmem[b.Preds[i].b.ID] {
562						f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].b.ID])
563					}
564				}
565			}
566		}
567	}
568
569	// Check that only one memory is live at any point.
570	if f.scheduled {
571		for _, b := range f.Blocks {
572			var mem *Value // the current live memory in the block
573			for _, v := range b.Values {
574				if v.Op == OpPhi {
575					if v.Type.IsMemory() {
576						mem = v
577					}
578					continue
579				}
580				if mem == nil && len(b.Preds) > 0 {
581					// If no mem phi, take mem of any predecessor.
582					mem = lastmem[b.Preds[0].b.ID]
583				}
584				for _, a := range v.Args {
585					if a.Type.IsMemory() && a != mem {
586						f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
587					}
588				}
589				if v.Type.IsMemory() {
590					mem = v
591				}
592			}
593		}
594	}
595
596	// Check that after scheduling, phis are always first in the block.
597	if f.scheduled {
598		for _, b := range f.Blocks {
599			seenNonPhi := false
600			for _, v := range b.Values {
601				switch v.Op {
602				case OpPhi:
603					if seenNonPhi {
604						f.Fatalf("phi after non-phi @ %s: %s", b, v)
605					}
606				default:
607					seenNonPhi = true
608				}
609			}
610		}
611	}
612}
613
614// domCheck reports whether x dominates y (including x==y).
615func domCheck(f *Func, sdom SparseTree, x, y *Block) bool {
616	if !sdom.IsAncestorEq(f.Entry, y) {
617		// unreachable - ignore
618		return true
619	}
620	return sdom.IsAncestorEq(x, y)
621}
622
623// isExactFloat32 reports whether x can be exactly represented as a float32.
624func isExactFloat32(x float64) bool {
625	// Check the mantissa is in range.
626	if bits.TrailingZeros64(math.Float64bits(x)) < 52-23 {
627		return false
628	}
629	// Check the exponent is in range. The mantissa check above is sufficient for NaN values.
630	return math.IsNaN(x) || x == float64(float32(x))
631}
632