Source file src/cmd/compile/internal/ssacompile/check.go

     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  
     5  package ssacompile
     6  
     7  import (
     8  	"math"
     9  	"math/bits"
    10  
    11  	"cmd/compile/internal/ir"
    12  	"cmd/compile/internal/ssa"
    13  	"cmd/compile/internal/ssa/block"
    14  	"cmd/compile/internal/ssa/ssaop"
    15  	"cmd/internal/obj/s390x"
    16  )
    17  
    18  // checkFunc checks invariants of f.
    19  func checkFunc(f *ssa.Func) {
    20  	blockMark := make([]bool, f.NumBlocks())
    21  	valueMark := make([]bool, f.NumValues())
    22  
    23  	for _, b := range f.Blocks {
    24  		if blockMark[b.ID] {
    25  			f.Fatalf("block %s appears twice in %s!", b, f.Name)
    26  		}
    27  		blockMark[b.ID] = true
    28  		if b.Func != f {
    29  			f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name)
    30  		}
    31  
    32  		for i, e := range b.Preds {
    33  			if se := e.B.Succs[e.I]; se.B != b || se.I != i {
    34  				f.Fatalf("block pred/succ not crosslinked correctly %d:%s %d:%s", i, b, se.I, se.B)
    35  			}
    36  		}
    37  		for i, e := range b.Succs {
    38  			if pe := e.B.Preds[e.I]; pe.B != b || pe.I != i {
    39  				f.Fatalf("block succ/pred not crosslinked correctly %d:%s %d:%s", i, b, pe.I, pe.B)
    40  			}
    41  		}
    42  
    43  		switch b.Kind {
    44  		case block.BlockExit:
    45  			if len(b.Succs) != 0 {
    46  				f.Fatalf("exit block %s has successors", b)
    47  			}
    48  			if b.NumControls() != 1 {
    49  				f.Fatalf("exit block %s has no control value", b)
    50  			}
    51  			if !b.Controls[0].Type.IsMemory() {
    52  				f.Fatalf("exit block %s has non-memory control value %s", b, b.Controls[0].LongString())
    53  			}
    54  		case block.BlockRet:
    55  			if len(b.Succs) != 0 {
    56  				f.Fatalf("ret block %s has successors", b)
    57  			}
    58  			if b.NumControls() != 1 {
    59  				f.Fatalf("ret block %s has nil control", b)
    60  			}
    61  			if !b.Controls[0].Type.IsMemory() {
    62  				f.Fatalf("ret block %s has non-memory control value %s", b, b.Controls[0].LongString())
    63  			}
    64  		case block.BlockRetJmp:
    65  			if len(b.Succs) != 0 {
    66  				f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
    67  			}
    68  			if b.NumControls() != 1 {
    69  				f.Fatalf("retjmp block %s has nil control", b)
    70  			}
    71  			if !b.Controls[0].Type.IsMemory() {
    72  				f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Controls[0].LongString())
    73  			}
    74  		case block.BlockPlain:
    75  			if len(b.Succs) != 1 {
    76  				f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
    77  			}
    78  			if b.NumControls() != 0 {
    79  				f.Fatalf("plain block %s has non-nil control %s", b, b.Controls[0].LongString())
    80  			}
    81  		case block.BlockIf:
    82  			if len(b.Succs) != 2 {
    83  				f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
    84  			}
    85  			if b.NumControls() != 1 {
    86  				f.Fatalf("if block %s has no control value", b)
    87  			}
    88  			if !b.Controls[0].Type.IsBoolean() {
    89  				f.Fatalf("if block %s has non-bool control value %s", b, b.Controls[0].LongString())
    90  			}
    91  		case block.BlockDefer:
    92  			if len(b.Succs) != 2 {
    93  				f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
    94  			}
    95  			if b.NumControls() != 1 {
    96  				f.Fatalf("defer block %s has no control value", b)
    97  			}
    98  			if !b.Controls[0].Type.IsMemory() {
    99  				f.Fatalf("defer block %s has non-memory control value %s", b, b.Controls[0].LongString())
   100  			}
   101  		case block.BlockFirst:
   102  			if len(b.Succs) != 2 {
   103  				f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
   104  			}
   105  			if b.NumControls() != 0 {
   106  				f.Fatalf("plain/dead block %s has a control value", b)
   107  			}
   108  		case block.BlockJumpTable:
   109  			if b.NumControls() != 1 {
   110  				f.Fatalf("jumpTable block %s has no control value", b)
   111  			}
   112  		}
   113  		if len(b.Succs) != 2 && b.Likely != ssa.BranchUnknown {
   114  			f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
   115  		}
   116  
   117  		for _, v := range b.Values {
   118  			// Check to make sure argument count makes sense (argLen of -1 indicates
   119  			// variable length args)
   120  			nArgs := ssaop.OpcodeTable[v.Op].ArgLen
   121  			if nArgs != -1 && int32(len(v.Args)) != nArgs {
   122  				f.Fatalf("value %s has %d args, expected %d", v.LongString(),
   123  					len(v.Args), nArgs)
   124  			}
   125  
   126  			// Check to make sure aux values make sense.
   127  			canHaveAux := false
   128  			canHaveAuxInt := false
   129  			// TODO: enforce types of Aux in this switch (like auxString does below)
   130  			switch ssaop.OpcodeTable[v.Op].AuxType {
   131  			case ssaop.AuxTypeNone:
   132  			case ssaop.AuxTypeBool:
   133  				if v.AuxInt < 0 || v.AuxInt > 1 {
   134  					f.Fatalf("bad bool AuxInt value for %v", v)
   135  				}
   136  				canHaveAuxInt = true
   137  			case ssaop.AuxTypeInt8:
   138  				if v.AuxInt != int64(int8(v.AuxInt)) {
   139  					f.Fatalf("bad int8 AuxInt value for %v", v)
   140  				}
   141  				canHaveAuxInt = true
   142  			case ssaop.AuxTypeInt16:
   143  				if v.AuxInt != int64(int16(v.AuxInt)) {
   144  					f.Fatalf("bad int16 AuxInt value for %v", v)
   145  				}
   146  				canHaveAuxInt = true
   147  			case ssaop.AuxTypeInt32:
   148  				if v.AuxInt != int64(int32(v.AuxInt)) {
   149  					f.Fatalf("bad int32 AuxInt value for %v", v)
   150  				}
   151  				canHaveAuxInt = true
   152  			case ssaop.AuxTypeInt64, ssaop.AuxTypeARM64BitField, ssaop.AuxTypeARM64ConditionalParams:
   153  				canHaveAuxInt = true
   154  			case ssaop.AuxTypeInt128:
   155  				// AuxInt must be zero, so leave canHaveAuxInt set to false.
   156  			case ssaop.AuxTypeUInt8:
   157  				// Cast to int8 due to requirement of AuxInt, check its comment for details.
   158  				if v.AuxInt != int64(int8(v.AuxInt)) {
   159  					f.Fatalf("bad uint8 AuxInt value for %v, saw %d but need %d", v, v.AuxInt, int64(int8(v.AuxInt)))
   160  				}
   161  				canHaveAuxInt = true
   162  			case ssaop.AuxTypeFloat32:
   163  				canHaveAuxInt = true
   164  				if math.IsNaN(v.AuxFloat()) {
   165  					f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
   166  				}
   167  				if !isExactFloat32(v.AuxFloat()) {
   168  					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
   169  				}
   170  			case ssaop.AuxTypeFloat64:
   171  				canHaveAuxInt = true
   172  				if math.IsNaN(v.AuxFloat()) {
   173  					f.Fatalf("value %v has an AuxInt that encodes a NaN", v)
   174  				}
   175  			case ssaop.AuxTypeString:
   176  				if _, ok := v.Aux.(ssa.StringAux); !ok {
   177  					f.Fatalf("value %v has Aux type %T, want string", v, v.Aux)
   178  				}
   179  				canHaveAux = true
   180  			case ssaop.AuxTypeCallOff:
   181  				canHaveAuxInt = true
   182  				fallthrough
   183  			case ssaop.AuxTypeCall:
   184  				if ac, ok := v.Aux.(*ssa.AuxCall); ok {
   185  					if v.Op == ssaop.OpStaticCall && ac.Fn == nil {
   186  						f.Fatalf("value %v has *AuxCall with nil Fn", v)
   187  					}
   188  				} else {
   189  					f.Fatalf("value %v has Aux type %T, want *AuxCall", v, v.Aux)
   190  				}
   191  				canHaveAux = true
   192  			case ssaop.AuxTypeNameOffsetInt8:
   193  				if _, ok := v.Aux.(*ssa.AuxNameOffset); !ok {
   194  					f.Fatalf("value %v has Aux type %T, want *AuxNameOffset", v, v.Aux)
   195  				}
   196  				canHaveAux = true
   197  				canHaveAuxInt = true
   198  			case ssaop.AuxTypeSym, ssaop.AuxTypeTyp:
   199  				canHaveAux = true
   200  			case ssaop.AuxTypeSymOff, ssaop.AuxTypeSymValAndOff, ssaop.AuxTypeTypSize:
   201  				canHaveAuxInt = true
   202  				canHaveAux = true
   203  			case ssaop.AuxTypeCCop:
   204  				if ssaop.OpcodeTable[ssaop.Op(v.AuxInt)].Name == "OpInvalid" {
   205  					f.Fatalf("value %v has an AuxInt value that is not a valid opcode", v)
   206  				}
   207  				canHaveAuxInt = true
   208  			case ssaop.AuxTypeS390XCCMask:
   209  				if _, ok := v.Aux.(s390x.CCMask); !ok {
   210  					f.Fatalf("bad type %T for S390XCCMask in %v", v.Aux, v)
   211  				}
   212  				canHaveAux = true
   213  			case ssaop.AuxTypeS390XRotateParams:
   214  				if _, ok := v.Aux.(s390x.RotateParams); !ok {
   215  					f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
   216  				}
   217  				canHaveAux = true
   218  			case ssaop.AuxTypeFlagConstant:
   219  				if v.AuxInt < 0 || v.AuxInt > 15 {
   220  					f.Fatalf("bad FlagConstant AuxInt value for %v", v)
   221  				}
   222  				canHaveAuxInt = true
   223  			case ssaop.AuxTypePanicBoundsC, ssaop.AuxTypePanicBoundsCC:
   224  				canHaveAux = true
   225  				canHaveAuxInt = true
   226  			case ssaop.AuxTypeSizeAndAlign:
   227  				if _, ok := v.Aux.(ssa.Int64Aux); !ok {
   228  					f.Fatalf("value %v has Aux type %T, want Int64Aux", v, v.Aux)
   229  				}
   230  				canHaveAux = true
   231  				canHaveAuxInt = true
   232  			default:
   233  				f.Fatalf("unknown aux type %T for %s", ssaop.OpcodeTable[v.Op].AuxType, v.Op)
   234  			}
   235  			if !canHaveAux && v.Aux != nil {
   236  				f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
   237  			}
   238  			if !canHaveAuxInt && v.AuxInt != 0 {
   239  				f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
   240  			}
   241  
   242  			for i, arg := range v.Args {
   243  				if arg == nil {
   244  					f.Fatalf("value %s has nil arg", v.LongString())
   245  				}
   246  				if v.Op != ssaop.OpPhi {
   247  					// For non-Phi ops, memory args must be last, if present
   248  					if arg.Type.IsMemory() && i != len(v.Args)-1 {
   249  						f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1)
   250  					}
   251  				}
   252  			}
   253  
   254  			if valueMark[v.ID] {
   255  				f.Fatalf("value %s appears twice!", v.LongString())
   256  			}
   257  			valueMark[v.ID] = true
   258  
   259  			if v.Block != b {
   260  				f.Fatalf("%s.block != %s", v, b)
   261  			}
   262  			if v.Op == ssaop.OpPhi && len(v.Args) != len(b.Preds) {
   263  				f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b)
   264  			}
   265  
   266  			if v.Op == ssaop.OpAddr {
   267  				if len(v.Args) == 0 {
   268  					f.Fatalf("no args for OpAddr %s", v.LongString())
   269  				}
   270  				if v.Args[0].Op != ssaop.OpSB {
   271  					f.Fatalf("bad arg to OpAddr %v", v)
   272  				}
   273  			}
   274  
   275  			if v.Op == ssaop.OpLocalAddr {
   276  				if len(v.Args) != 2 {
   277  					f.Fatalf("wrong # of args for OpLocalAddr %s", v.LongString())
   278  				}
   279  				if v.Args[0].Op != ssaop.OpSP {
   280  					f.Fatalf("bad arg 0 to OpLocalAddr %v", v)
   281  				}
   282  				if !v.Args[1].Type.IsMemory() {
   283  					f.Fatalf("bad arg 1 to OpLocalAddr %v", v)
   284  				}
   285  			}
   286  
   287  			if (v.Op == ssaop.OpStructMake || v.Op == ssaop.OpArrayMake1) && v.Type.Size() == 0 {
   288  				f.Fatalf("zero-sized Make; use Empty instead %v", v)
   289  			}
   290  
   291  			if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() {
   292  				f.Fatalf("unexpected floating-point type %v", v.LongString())
   293  			}
   294  
   295  			// Check types.
   296  			// TODO: more type checks?
   297  			switch c := f.Config; v.Op {
   298  			case ssaop.OpSP, ssaop.OpSB:
   299  				if v.Type != c.Types.Uintptr {
   300  					f.Fatalf("bad %s type: want uintptr, have %s",
   301  						v.Op, v.Type.String())
   302  				}
   303  			case ssaop.OpStringLen:
   304  				if v.Type != c.Types.Int {
   305  					f.Fatalf("bad %s type: want int, have %s",
   306  						v.Op, v.Type.String())
   307  				}
   308  			case ssaop.OpLoad:
   309  				if !v.Args[1].Type.IsMemory() {
   310  					f.Fatalf("bad arg 1 type to %s: want mem, have %s",
   311  						v.Op, v.Args[1].Type.String())
   312  				}
   313  			case ssaop.OpStore:
   314  				if !v.Type.IsMemory() {
   315  					f.Fatalf("bad %s type: want mem, have %s",
   316  						v.Op, v.Type.String())
   317  				}
   318  				if !v.Args[2].Type.IsMemory() {
   319  					f.Fatalf("bad arg 2 type to %s: want mem, have %s",
   320  						v.Op, v.Args[2].Type.String())
   321  				}
   322  			case ssaop.OpCondSelect:
   323  				if !v.Args[2].Type.IsBoolean() {
   324  					f.Fatalf("bad arg 2 type to %s: want boolean, have %s",
   325  						v.Op, v.Args[2].Type.String())
   326  				}
   327  			case ssaop.OpAddPtr:
   328  				if !v.Args[0].Type.IsPtrShaped() && v.Args[0].Type != c.Types.Uintptr {
   329  					f.Fatalf("bad arg 0 type to %s: want ptr, have %s", v.Op, v.Args[0].LongString())
   330  				}
   331  				if !v.Args[1].Type.IsInteger() {
   332  					f.Fatalf("bad arg 1 type to %s: want integer, have %s", v.Op, v.Args[1].LongString())
   333  				}
   334  			case ssaop.OpVarDef:
   335  				n := v.Aux.(*ir.Name)
   336  				if !n.Type().HasPointers() && !ssa.IsMergeCandidate(n) {
   337  					f.Fatalf("vardef must be merge candidate or have pointer type %s", v.Aux.(*ir.Name).Type().String())
   338  				}
   339  			case ssaop.OpNilCheck:
   340  				// nil checks have pointer type before scheduling, and
   341  				// void type after scheduling.
   342  				if f.Scheduled {
   343  					if v.Uses != 0 {
   344  						f.Fatalf("nilcheck must have 0 uses %s", v.Uses)
   345  					}
   346  					if !v.Type.IsVoid() {
   347  						f.Fatalf("nilcheck must have void type %s", v.Type.String())
   348  					}
   349  				} else {
   350  					if !v.Type.IsPtrShaped() && !v.Type.IsUintptr() {
   351  						f.Fatalf("nilcheck must have pointer type %s", v.Type.String())
   352  					}
   353  				}
   354  				if !v.Args[0].Type.IsPtrShaped() && !v.Args[0].Type.IsUintptr() {
   355  					f.Fatalf("nilcheck must have argument of pointer type %s", v.Args[0].Type.String())
   356  				}
   357  				if !v.Args[1].Type.IsMemory() {
   358  					f.Fatalf("bad arg 1 type to %s: want mem, have %s",
   359  						v.Op, v.Args[1].Type.String())
   360  				}
   361  			}
   362  			// Check size of args.
   363  			// This list isn't exhaustive, just the common ops.
   364  			// It also can't handle ops with args of different types, like shifts.
   365  			var argSize int64
   366  			switch v.Op {
   367  			case ssaop.OpAdd8, ssaop.OpSub8, ssaop.OpMul8, ssaop.OpDiv8, ssaop.OpDiv8u, ssaop.OpMod8, ssaop.OpMod8u,
   368  				ssaop.OpAnd8, ssaop.OpOr8, ssaop.OpXor8,
   369  				ssaop.OpEq8, ssaop.OpNeq8, ssaop.OpLess8, ssaop.OpLeq8,
   370  				ssaop.OpNeg8, ssaop.OpCom8,
   371  				ssaop.OpSignExt8to16, ssaop.OpSignExt8to32, ssaop.OpSignExt8to64,
   372  				ssaop.OpZeroExt8to16, ssaop.OpZeroExt8to32, ssaop.OpZeroExt8to64:
   373  				argSize = 1
   374  			case ssaop.OpAdd16, ssaop.OpSub16, ssaop.OpMul16, ssaop.OpDiv16, ssaop.OpDiv16u, ssaop.OpMod16, ssaop.OpMod16u,
   375  				ssaop.OpAnd16, ssaop.OpOr16, ssaop.OpXor16,
   376  				ssaop.OpEq16, ssaop.OpNeq16, ssaop.OpLess16, ssaop.OpLeq16,
   377  				ssaop.OpNeg16, ssaop.OpCom16,
   378  				ssaop.OpSignExt16to32, ssaop.OpSignExt16to64,
   379  				ssaop.OpZeroExt16to32, ssaop.OpZeroExt16to64,
   380  				ssaop.OpTrunc16to8:
   381  				argSize = 2
   382  			case ssaop.OpAdd32, ssaop.OpSub32, ssaop.OpMul32, ssaop.OpDiv32, ssaop.OpDiv32u, ssaop.OpMod32, ssaop.OpMod32u,
   383  				ssaop.OpAnd32, ssaop.OpOr32, ssaop.OpXor32,
   384  				ssaop.OpEq32, ssaop.OpNeq32, ssaop.OpLess32, ssaop.OpLeq32,
   385  				ssaop.OpNeg32, ssaop.OpCom32,
   386  				ssaop.OpSignExt32to64, ssaop.OpZeroExt32to64,
   387  				ssaop.OpTrunc32to8, ssaop.OpTrunc32to16:
   388  				argSize = 4
   389  			case ssaop.OpAdd64, ssaop.OpSub64, ssaop.OpMul64, ssaop.OpDiv64, ssaop.OpDiv64u, ssaop.OpMod64, ssaop.OpMod64u,
   390  				ssaop.OpAnd64, ssaop.OpOr64, ssaop.OpXor64,
   391  				ssaop.OpEq64, ssaop.OpNeq64, ssaop.OpLess64, ssaop.OpLeq64,
   392  				ssaop.OpNeg64, ssaop.OpCom64,
   393  				ssaop.OpTrunc64to8, ssaop.OpTrunc64to16, ssaop.OpTrunc64to32:
   394  				argSize = 8
   395  			}
   396  			if argSize != 0 {
   397  				for i, arg := range v.Args {
   398  					if arg.Type.Size() != argSize {
   399  						f.Fatalf("arg %d to %s (%v) should be %d bytes in size, it is %s", i, v.Op, v, argSize, arg.Type.String())
   400  					}
   401  				}
   402  			}
   403  
   404  			// TODO: check for cycles in values
   405  		}
   406  	}
   407  
   408  	// Check to make sure all Blocks referenced are in the function.
   409  	if !blockMark[f.Entry.ID] {
   410  		f.Fatalf("entry block %v is missing", f.Entry)
   411  	}
   412  	for _, b := range f.Blocks {
   413  		for _, c := range b.Preds {
   414  			if !blockMark[c.B.ID] {
   415  				f.Fatalf("predecessor block %v for %v is missing", c, b)
   416  			}
   417  		}
   418  		for _, c := range b.Succs {
   419  			if !blockMark[c.B.ID] {
   420  				f.Fatalf("successor block %v for %v is missing", c, b)
   421  			}
   422  		}
   423  	}
   424  
   425  	if len(f.Entry.Preds) > 0 {
   426  		f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds)
   427  	}
   428  
   429  	// Check to make sure all Values referenced are in the function.
   430  	for _, b := range f.Blocks {
   431  		for _, v := range b.Values {
   432  			for i, a := range v.Args {
   433  				if !valueMark[a.ID] {
   434  					f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
   435  				}
   436  			}
   437  		}
   438  		for _, c := range b.ControlValues() {
   439  			if !valueMark[c.ID] {
   440  				f.Fatalf("control value for %s is missing: %v", b, c)
   441  			}
   442  		}
   443  	}
   444  	for b := f.FreeBlocks; b != nil; b = b.Succstorage[0].B {
   445  		if blockMark[b.ID] {
   446  			f.Fatalf("used block b%d in free list", b.ID)
   447  		}
   448  	}
   449  	for v := f.FreeValues; v != nil; v = v.Argstorage[0] {
   450  		if valueMark[v.ID] {
   451  			f.Fatalf("used value v%d in free list", v.ID)
   452  		}
   453  	}
   454  
   455  	// Check to make sure all args dominate uses.
   456  	sdom := f.Sdom()
   457  	for _, b := range f.Blocks {
   458  		for _, v := range b.Values {
   459  			for i, arg := range v.Args {
   460  				x := arg.Block
   461  				y := b
   462  				if v.Op == ssaop.OpPhi {
   463  					y = b.Preds[i].B
   464  				}
   465  				if !domCheck(f, sdom, x, y) {
   466  					f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString())
   467  				}
   468  			}
   469  		}
   470  		for _, c := range b.ControlValues() {
   471  			if !domCheck(f, sdom, c.Block, b) {
   472  				f.Fatalf("control value %s for %s doesn't dominate", c, b)
   473  			}
   474  		}
   475  	}
   476  
   477  	// Check loop construction
   478  	if f.RegAlloc == nil && f.Pass != nil { // non-nil pass allows better-targeted debug printing
   479  		ln := f.Loopnest()
   480  		if !ln.HasIrreducible {
   481  			po := f.Postorder() // use po to avoid unreachable blocks.
   482  			for _, b := range po {
   483  				for _, s := range b.Succs {
   484  					bb := s.Block()
   485  					if ln.B2L[b.ID] == nil && ln.B2L[bb.ID] != nil && bb != ln.B2L[bb.ID].Header {
   486  						f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String())
   487  					}
   488  					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]) {
   489  						f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String())
   490  					}
   491  				}
   492  			}
   493  		}
   494  	}
   495  
   496  	// Check use counts
   497  	uses := make([]int32, f.NumValues())
   498  	for _, b := range f.Blocks {
   499  		for _, v := range b.Values {
   500  			for _, a := range v.Args {
   501  				uses[a.ID]++
   502  			}
   503  		}
   504  		for _, c := range b.ControlValues() {
   505  			uses[c.ID]++
   506  		}
   507  	}
   508  	for _, b := range f.Blocks {
   509  		for _, v := range b.Values {
   510  			if v.Uses != uses[v.ID] {
   511  				f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
   512  			}
   513  		}
   514  	}
   515  
   516  	memCheck(f)
   517  }
   518  
   519  func memCheck(f *ssa.Func) {
   520  	// Check that if a tuple has a memory type, it is second.
   521  	for _, b := range f.Blocks {
   522  		for _, v := range b.Values {
   523  			if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
   524  				f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
   525  			}
   526  		}
   527  	}
   528  
   529  	// Single live memory checks.
   530  	// These checks only work if there are no memory copies.
   531  	// (Memory copies introduce ambiguity about which mem value is really live.
   532  	// probably fixable, but it's easier to avoid the problem.)
   533  	// For the same reason, disable this check if some memory ops are unused.
   534  	for _, b := range f.Blocks {
   535  		for _, v := range b.Values {
   536  			if (v.Op == ssaop.OpCopy || v.Uses == 0) && v.Type.IsMemory() {
   537  				return
   538  			}
   539  		}
   540  		if b != f.Entry && len(b.Preds) == 0 {
   541  			return
   542  		}
   543  	}
   544  
   545  	// Compute live memory at the end of each block.
   546  	lastmem := make([]*ssa.Value, f.NumBlocks())
   547  	ss := ssa.NewSparseSet(f.NumValues())
   548  	for _, b := range f.Blocks {
   549  		// Mark overwritten memory values. Those are args of other
   550  		// ops that generate memory values.
   551  		ss.Clear()
   552  		for _, v := range b.Values {
   553  			if v.Op == ssaop.OpPhi || !v.Type.IsMemory() {
   554  				continue
   555  			}
   556  			if m := v.MemoryArg(); m != nil {
   557  				ss.Add(m.ID)
   558  			}
   559  		}
   560  		// There should be at most one remaining unoverwritten memory value.
   561  		for _, v := range b.Values {
   562  			if !v.Type.IsMemory() {
   563  				continue
   564  			}
   565  			if ss.Contains(v.ID) {
   566  				continue
   567  			}
   568  			if lastmem[b.ID] != nil {
   569  				f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v)
   570  			}
   571  			lastmem[b.ID] = v
   572  		}
   573  		// If there is no remaining memory value, that means there was no memory update.
   574  		// Take any memory arg.
   575  		if lastmem[b.ID] == nil {
   576  			for _, v := range b.Values {
   577  				if v.Op == ssaop.OpPhi {
   578  					continue
   579  				}
   580  				m := v.MemoryArg()
   581  				if m == nil {
   582  					continue
   583  				}
   584  				if lastmem[b.ID] != nil && lastmem[b.ID] != m {
   585  					f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m)
   586  				}
   587  				lastmem[b.ID] = m
   588  			}
   589  		}
   590  	}
   591  	// Propagate last live memory through storeless blocks.
   592  	for {
   593  		changed := false
   594  		for _, b := range f.Blocks {
   595  			if lastmem[b.ID] != nil {
   596  				continue
   597  			}
   598  			for _, e := range b.Preds {
   599  				p := e.B
   600  				if lastmem[p.ID] != nil {
   601  					lastmem[b.ID] = lastmem[p.ID]
   602  					changed = true
   603  					break
   604  				}
   605  			}
   606  		}
   607  		if !changed {
   608  			break
   609  		}
   610  	}
   611  	// Check merge points.
   612  	for _, b := range f.Blocks {
   613  		for _, v := range b.Values {
   614  			if v.Op == ssaop.OpPhi && v.Type.IsMemory() {
   615  				for i, a := range v.Args {
   616  					if a != lastmem[b.Preds[i].B.ID] {
   617  						f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].B.ID])
   618  					}
   619  				}
   620  			}
   621  		}
   622  	}
   623  
   624  	// Check that only one memory is live at any point.
   625  	if f.Scheduled {
   626  		for _, b := range f.Blocks {
   627  			var mem *ssa.Value // the current live memory in the block
   628  			for _, v := range b.Values {
   629  				if v.Op == ssaop.OpPhi {
   630  					if v.Type.IsMemory() {
   631  						mem = v
   632  					}
   633  					continue
   634  				}
   635  				if mem == nil && len(b.Preds) > 0 {
   636  					// If no mem phi, take mem of any predecessor.
   637  					mem = lastmem[b.Preds[0].B.ID]
   638  				}
   639  				for _, a := range v.Args {
   640  					if a.Type.IsMemory() && a != mem {
   641  						f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
   642  					}
   643  				}
   644  				if v.Type.IsMemory() {
   645  					mem = v
   646  				}
   647  			}
   648  		}
   649  	}
   650  
   651  	// Check that after scheduling, phis are always first in the block.
   652  	if f.Scheduled {
   653  		for _, b := range f.Blocks {
   654  			seenNonPhi := false
   655  			for _, v := range b.Values {
   656  				switch v.Op {
   657  				case ssaop.OpPhi:
   658  					if seenNonPhi {
   659  						f.Fatalf("phi after non-phi @ %s: %s", b, v)
   660  					}
   661  				default:
   662  					seenNonPhi = true
   663  				}
   664  			}
   665  		}
   666  	}
   667  }
   668  
   669  // domCheck reports whether x dominates y (including x==y).
   670  func domCheck(f *ssa.Func, sdom ssa.SparseTree, x, y *ssa.Block) bool {
   671  	if !sdom.IsAncestorEq(f.Entry, y) {
   672  		// unreachable - ignore
   673  		return true
   674  	}
   675  	return sdom.IsAncestorEq(x, y)
   676  }
   677  
   678  // isExactFloat32 reports whether x can be exactly represented as a float32.
   679  func isExactFloat32(x float64) bool {
   680  	// Check the mantissa is in range.
   681  	if bits.TrailingZeros64(math.Float64bits(x)) < 52-23 {
   682  		return false
   683  	}
   684  	// Check the exponent is in range. The mantissa check above is sufficient for NaN values.
   685  	return math.IsNaN(x) || x == float64(float32(x))
   686  }
   687  

View as plain text