...

Source file src/pkg/cmd/compile/internal/ssa/decompose.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 ssa
     6	
     7	import (
     8		"cmd/compile/internal/types"
     9	)
    10	
    11	// decompose converts phi ops on compound builtin types into phi
    12	// ops on simple types, then invokes rewrite rules to decompose
    13	// other ops on those types.
    14	func decomposeBuiltIn(f *Func) {
    15		// Decompose phis
    16		for _, b := range f.Blocks {
    17			for _, v := range b.Values {
    18				if v.Op != OpPhi {
    19					continue
    20				}
    21				decomposeBuiltInPhi(v)
    22			}
    23		}
    24	
    25		// Decompose other values
    26		applyRewrite(f, rewriteBlockdec, rewriteValuedec)
    27		if f.Config.RegSize == 4 {
    28			applyRewrite(f, rewriteBlockdec64, rewriteValuedec64)
    29		}
    30	
    31		// Split up named values into their components.
    32		var newNames []LocalSlot
    33		for _, name := range f.Names {
    34			t := name.Type
    35			switch {
    36			case t.IsInteger() && t.Size() > f.Config.RegSize:
    37				hiName, loName := f.fe.SplitInt64(name)
    38				newNames = append(newNames, hiName, loName)
    39				for _, v := range f.NamedValues[name] {
    40					if v.Op != OpInt64Make {
    41						continue
    42					}
    43					f.NamedValues[hiName] = append(f.NamedValues[hiName], v.Args[0])
    44					f.NamedValues[loName] = append(f.NamedValues[loName], v.Args[1])
    45				}
    46				delete(f.NamedValues, name)
    47			case t.IsComplex():
    48				rName, iName := f.fe.SplitComplex(name)
    49				newNames = append(newNames, rName, iName)
    50				for _, v := range f.NamedValues[name] {
    51					if v.Op != OpComplexMake {
    52						continue
    53					}
    54					f.NamedValues[rName] = append(f.NamedValues[rName], v.Args[0])
    55					f.NamedValues[iName] = append(f.NamedValues[iName], v.Args[1])
    56	
    57				}
    58				delete(f.NamedValues, name)
    59			case t.IsString():
    60				ptrName, lenName := f.fe.SplitString(name)
    61				newNames = append(newNames, ptrName, lenName)
    62				for _, v := range f.NamedValues[name] {
    63					if v.Op != OpStringMake {
    64						continue
    65					}
    66					f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
    67					f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
    68				}
    69				delete(f.NamedValues, name)
    70			case t.IsSlice():
    71				ptrName, lenName, capName := f.fe.SplitSlice(name)
    72				newNames = append(newNames, ptrName, lenName, capName)
    73				for _, v := range f.NamedValues[name] {
    74					if v.Op != OpSliceMake {
    75						continue
    76					}
    77					f.NamedValues[ptrName] = append(f.NamedValues[ptrName], v.Args[0])
    78					f.NamedValues[lenName] = append(f.NamedValues[lenName], v.Args[1])
    79					f.NamedValues[capName] = append(f.NamedValues[capName], v.Args[2])
    80				}
    81				delete(f.NamedValues, name)
    82			case t.IsInterface():
    83				typeName, dataName := f.fe.SplitInterface(name)
    84				newNames = append(newNames, typeName, dataName)
    85				for _, v := range f.NamedValues[name] {
    86					if v.Op != OpIMake {
    87						continue
    88					}
    89					f.NamedValues[typeName] = append(f.NamedValues[typeName], v.Args[0])
    90					f.NamedValues[dataName] = append(f.NamedValues[dataName], v.Args[1])
    91				}
    92				delete(f.NamedValues, name)
    93			case t.IsFloat():
    94				// floats are never decomposed, even ones bigger than RegSize
    95				newNames = append(newNames, name)
    96			case t.Size() > f.Config.RegSize:
    97				f.Fatalf("undecomposed named type %s %v", name, t)
    98			default:
    99				newNames = append(newNames, name)
   100			}
   101		}
   102		f.Names = newNames
   103	}
   104	
   105	func decomposeBuiltInPhi(v *Value) {
   106		switch {
   107		case v.Type.IsInteger() && v.Type.Size() > v.Block.Func.Config.RegSize:
   108			decomposeInt64Phi(v)
   109		case v.Type.IsComplex():
   110			decomposeComplexPhi(v)
   111		case v.Type.IsString():
   112			decomposeStringPhi(v)
   113		case v.Type.IsSlice():
   114			decomposeSlicePhi(v)
   115		case v.Type.IsInterface():
   116			decomposeInterfacePhi(v)
   117		case v.Type.IsFloat():
   118			// floats are never decomposed, even ones bigger than RegSize
   119		case v.Type.Size() > v.Block.Func.Config.RegSize:
   120			v.Fatalf("undecomposed type %s", v.Type)
   121		}
   122	}
   123	
   124	func decomposeStringPhi(v *Value) {
   125		types := &v.Block.Func.Config.Types
   126		ptrType := types.BytePtr
   127		lenType := types.Int
   128	
   129		ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   130		len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   131		for _, a := range v.Args {
   132			ptr.AddArg(a.Block.NewValue1(v.Pos, OpStringPtr, ptrType, a))
   133			len.AddArg(a.Block.NewValue1(v.Pos, OpStringLen, lenType, a))
   134		}
   135		v.reset(OpStringMake)
   136		v.AddArg(ptr)
   137		v.AddArg(len)
   138	}
   139	
   140	func decomposeSlicePhi(v *Value) {
   141		types := &v.Block.Func.Config.Types
   142		ptrType := types.BytePtr
   143		lenType := types.Int
   144	
   145		ptr := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   146		len := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   147		cap := v.Block.NewValue0(v.Pos, OpPhi, lenType)
   148		for _, a := range v.Args {
   149			ptr.AddArg(a.Block.NewValue1(v.Pos, OpSlicePtr, ptrType, a))
   150			len.AddArg(a.Block.NewValue1(v.Pos, OpSliceLen, lenType, a))
   151			cap.AddArg(a.Block.NewValue1(v.Pos, OpSliceCap, lenType, a))
   152		}
   153		v.reset(OpSliceMake)
   154		v.AddArg(ptr)
   155		v.AddArg(len)
   156		v.AddArg(cap)
   157	}
   158	
   159	func decomposeInt64Phi(v *Value) {
   160		cfgtypes := &v.Block.Func.Config.Types
   161		var partType *types.Type
   162		if v.Type.IsSigned() {
   163			partType = cfgtypes.Int32
   164		} else {
   165			partType = cfgtypes.UInt32
   166		}
   167	
   168		hi := v.Block.NewValue0(v.Pos, OpPhi, partType)
   169		lo := v.Block.NewValue0(v.Pos, OpPhi, cfgtypes.UInt32)
   170		for _, a := range v.Args {
   171			hi.AddArg(a.Block.NewValue1(v.Pos, OpInt64Hi, partType, a))
   172			lo.AddArg(a.Block.NewValue1(v.Pos, OpInt64Lo, cfgtypes.UInt32, a))
   173		}
   174		v.reset(OpInt64Make)
   175		v.AddArg(hi)
   176		v.AddArg(lo)
   177	}
   178	
   179	func decomposeComplexPhi(v *Value) {
   180		cfgtypes := &v.Block.Func.Config.Types
   181		var partType *types.Type
   182		switch z := v.Type.Size(); z {
   183		case 8:
   184			partType = cfgtypes.Float32
   185		case 16:
   186			partType = cfgtypes.Float64
   187		default:
   188			v.Fatalf("decomposeComplexPhi: bad complex size %d", z)
   189		}
   190	
   191		real := v.Block.NewValue0(v.Pos, OpPhi, partType)
   192		imag := v.Block.NewValue0(v.Pos, OpPhi, partType)
   193		for _, a := range v.Args {
   194			real.AddArg(a.Block.NewValue1(v.Pos, OpComplexReal, partType, a))
   195			imag.AddArg(a.Block.NewValue1(v.Pos, OpComplexImag, partType, a))
   196		}
   197		v.reset(OpComplexMake)
   198		v.AddArg(real)
   199		v.AddArg(imag)
   200	}
   201	
   202	func decomposeInterfacePhi(v *Value) {
   203		uintptrType := v.Block.Func.Config.Types.Uintptr
   204		ptrType := v.Block.Func.Config.Types.BytePtr
   205	
   206		itab := v.Block.NewValue0(v.Pos, OpPhi, uintptrType)
   207		data := v.Block.NewValue0(v.Pos, OpPhi, ptrType)
   208		for _, a := range v.Args {
   209			itab.AddArg(a.Block.NewValue1(v.Pos, OpITab, uintptrType, a))
   210			data.AddArg(a.Block.NewValue1(v.Pos, OpIData, ptrType, a))
   211		}
   212		v.reset(OpIMake)
   213		v.AddArg(itab)
   214		v.AddArg(data)
   215	}
   216	
   217	func decomposeArgs(f *Func) {
   218		applyRewrite(f, rewriteBlockdecArgs, rewriteValuedecArgs)
   219	}
   220	
   221	func decomposeUser(f *Func) {
   222		for _, b := range f.Blocks {
   223			for _, v := range b.Values {
   224				if v.Op != OpPhi {
   225					continue
   226				}
   227				decomposeUserPhi(v)
   228			}
   229		}
   230		// Split up named values into their components.
   231		i := 0
   232		var newNames []LocalSlot
   233		for _, name := range f.Names {
   234			t := name.Type
   235			switch {
   236			case t.IsStruct():
   237				newNames = decomposeUserStructInto(f, name, newNames)
   238			case t.IsArray():
   239				newNames = decomposeUserArrayInto(f, name, newNames)
   240			default:
   241				f.Names[i] = name
   242				i++
   243			}
   244		}
   245		f.Names = f.Names[:i]
   246		f.Names = append(f.Names, newNames...)
   247	}
   248	
   249	// decomposeUserArrayInto creates names for the element(s) of arrays referenced
   250	// by name where possible, and appends those new names to slots, which is then
   251	// returned.
   252	func decomposeUserArrayInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
   253		t := name.Type
   254		if t.NumElem() == 0 {
   255			// TODO(khr): Not sure what to do here.  Probably nothing.
   256			// Names for empty arrays aren't important.
   257			return slots
   258		}
   259		if t.NumElem() != 1 {
   260			// shouldn't get here due to CanSSA
   261			f.Fatalf("array not of size 1")
   262		}
   263		elemName := f.fe.SplitArray(name)
   264		for _, v := range f.NamedValues[name] {
   265			if v.Op != OpArrayMake1 {
   266				continue
   267			}
   268			f.NamedValues[elemName] = append(f.NamedValues[elemName], v.Args[0])
   269		}
   270		// delete the name for the array as a whole
   271		delete(f.NamedValues, name)
   272	
   273		if t.Elem().IsArray() {
   274			return decomposeUserArrayInto(f, elemName, slots)
   275		} else if t.Elem().IsStruct() {
   276			return decomposeUserStructInto(f, elemName, slots)
   277		}
   278	
   279		return append(slots, elemName)
   280	}
   281	
   282	// decomposeUserStructInto creates names for the fields(s) of structs referenced
   283	// by name where possible, and appends those new names to slots, which is then
   284	// returned.
   285	func decomposeUserStructInto(f *Func, name LocalSlot, slots []LocalSlot) []LocalSlot {
   286		fnames := []LocalSlot{} // slots for struct in name
   287		t := name.Type
   288		n := t.NumFields()
   289	
   290		for i := 0; i < n; i++ {
   291			fs := f.fe.SplitStruct(name, i)
   292			fnames = append(fnames, fs)
   293			// arrays and structs will be decomposed further, so
   294			// there's no need to record a name
   295			if !fs.Type.IsArray() && !fs.Type.IsStruct() {
   296				slots = append(slots, fs)
   297			}
   298		}
   299	
   300		makeOp := StructMakeOp(n)
   301		// create named values for each struct field
   302		for _, v := range f.NamedValues[name] {
   303			if v.Op != makeOp {
   304				continue
   305			}
   306			for i := 0; i < len(fnames); i++ {
   307				f.NamedValues[fnames[i]] = append(f.NamedValues[fnames[i]], v.Args[i])
   308			}
   309		}
   310		// remove the name of the struct as a whole
   311		delete(f.NamedValues, name)
   312	
   313		// now that this f.NamedValues contains values for the struct
   314		// fields, recurse into nested structs
   315		for i := 0; i < n; i++ {
   316			if name.Type.FieldType(i).IsStruct() {
   317				slots = decomposeUserStructInto(f, fnames[i], slots)
   318				delete(f.NamedValues, fnames[i])
   319			} else if name.Type.FieldType(i).IsArray() {
   320				slots = decomposeUserArrayInto(f, fnames[i], slots)
   321				delete(f.NamedValues, fnames[i])
   322			}
   323		}
   324		return slots
   325	}
   326	func decomposeUserPhi(v *Value) {
   327		switch {
   328		case v.Type.IsStruct():
   329			decomposeStructPhi(v)
   330		case v.Type.IsArray():
   331			decomposeArrayPhi(v)
   332		}
   333	}
   334	
   335	// decomposeStructPhi replaces phi-of-struct with structmake(phi-for-each-field),
   336	// and then recursively decomposes the phis for each field.
   337	func decomposeStructPhi(v *Value) {
   338		t := v.Type
   339		n := t.NumFields()
   340		var fields [MaxStruct]*Value
   341		for i := 0; i < n; i++ {
   342			fields[i] = v.Block.NewValue0(v.Pos, OpPhi, t.FieldType(i))
   343		}
   344		for _, a := range v.Args {
   345			for i := 0; i < n; i++ {
   346				fields[i].AddArg(a.Block.NewValue1I(v.Pos, OpStructSelect, t.FieldType(i), int64(i), a))
   347			}
   348		}
   349		v.reset(StructMakeOp(n))
   350		v.AddArgs(fields[:n]...)
   351	
   352		// Recursively decompose phis for each field.
   353		for _, f := range fields[:n] {
   354			decomposeUserPhi(f)
   355		}
   356	}
   357	
   358	// decomposeArrayPhi replaces phi-of-array with arraymake(phi-of-array-element),
   359	// and then recursively decomposes the element phi.
   360	func decomposeArrayPhi(v *Value) {
   361		t := v.Type
   362		if t.NumElem() == 0 {
   363			v.reset(OpArrayMake0)
   364			return
   365		}
   366		if t.NumElem() != 1 {
   367			v.Fatalf("SSAable array must have no more than 1 element")
   368		}
   369		elem := v.Block.NewValue0(v.Pos, OpPhi, t.Elem())
   370		for _, a := range v.Args {
   371			elem.AddArg(a.Block.NewValue1I(v.Pos, OpArraySelect, t.Elem(), 0, a))
   372		}
   373		v.reset(OpArrayMake1)
   374		v.AddArg(elem)
   375	
   376		// Recursively decompose elem phi.
   377		decomposeUserPhi(elem)
   378	}
   379	
   380	// MaxStruct is the maximum number of fields a struct
   381	// can have and still be SSAable.
   382	const MaxStruct = 4
   383	
   384	// StructMakeOp returns the opcode to construct a struct with the
   385	// given number of fields.
   386	func StructMakeOp(nf int) Op {
   387		switch nf {
   388		case 0:
   389			return OpStructMake0
   390		case 1:
   391			return OpStructMake1
   392		case 2:
   393			return OpStructMake2
   394		case 3:
   395			return OpStructMake3
   396		case 4:
   397			return OpStructMake4
   398		}
   399		panic("too many fields in an SSAable struct")
   400	}
   401	

View as plain text