github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/ssa/decompose.go (about) 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 // decompose converts phi ops on compound builtin types into phi 8 // ops on simple types. 9 // (The remaining compound ops are decomposed with rewrite rules.) 10 func decomposeBuiltIn(f *Func) { 11 for _, b := range f.Blocks { 12 for _, v := range b.Values { 13 if v.Op != OpPhi { 14 continue 15 } 16 decomposeBuiltInPhi(v) 17 } 18 } 19 20 // Split up named values into their components. 21 // NOTE: the component values we are making are dead at this point. 22 // We must do the opt pass before any deadcode elimination or we will 23 // lose the name->value correspondence. 24 for _, name := range f.Names { 25 t := name.Type 26 switch { 27 case t.IsComplex(): 28 var elemType Type 29 if t.Size() == 16 { 30 elemType = f.Config.fe.TypeFloat64() 31 } else { 32 elemType = f.Config.fe.TypeFloat32() 33 } 34 rName, iName := f.Config.fe.SplitComplex(name) 35 f.Names = append(f.Names, rName, iName) 36 for _, v := range f.NamedValues[name] { 37 r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v) 38 i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v) 39 f.NamedValues[rName] = append(f.NamedValues[rName], r) 40 f.NamedValues[iName] = append(f.NamedValues[iName], i) 41 } 42 case t.IsString(): 43 ptrType := f.Config.fe.TypeBytePtr() 44 lenType := f.Config.fe.TypeInt() 45 ptrName, lenName := f.Config.fe.SplitString(name) 46 f.Names = append(f.Names, ptrName, lenName) 47 for _, v := range f.NamedValues[name] { 48 ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v) 49 len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v) 50 f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) 51 f.NamedValues[lenName] = append(f.NamedValues[lenName], len) 52 } 53 case t.IsSlice(): 54 ptrType := f.Config.fe.TypeBytePtr() 55 lenType := f.Config.fe.TypeInt() 56 ptrName, lenName, capName := f.Config.fe.SplitSlice(name) 57 f.Names = append(f.Names, ptrName, lenName, capName) 58 for _, v := range f.NamedValues[name] { 59 ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v) 60 len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v) 61 cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v) 62 f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) 63 f.NamedValues[lenName] = append(f.NamedValues[lenName], len) 64 f.NamedValues[capName] = append(f.NamedValues[capName], cap) 65 } 66 case t.IsInterface(): 67 ptrType := f.Config.fe.TypeBytePtr() 68 typeName, dataName := f.Config.fe.SplitInterface(name) 69 f.Names = append(f.Names, typeName, dataName) 70 for _, v := range f.NamedValues[name] { 71 typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v) 72 data := v.Block.NewValue1(v.Line, OpIData, ptrType, v) 73 f.NamedValues[typeName] = append(f.NamedValues[typeName], typ) 74 f.NamedValues[dataName] = append(f.NamedValues[dataName], data) 75 } 76 case t.Size() > f.Config.IntSize: 77 f.Unimplementedf("undecomposed named type %s", t) 78 } 79 } 80 } 81 82 func decomposeBuiltInPhi(v *Value) { 83 // TODO: decompose 64-bit ops on 32-bit archs? 84 switch { 85 case v.Type.IsComplex(): 86 decomposeComplexPhi(v) 87 case v.Type.IsString(): 88 decomposeStringPhi(v) 89 case v.Type.IsSlice(): 90 decomposeSlicePhi(v) 91 case v.Type.IsInterface(): 92 decomposeInterfacePhi(v) 93 case v.Type.Size() > v.Block.Func.Config.IntSize: 94 v.Unimplementedf("undecomposed type %s", v.Type) 95 } 96 } 97 98 func decomposeStringPhi(v *Value) { 99 fe := v.Block.Func.Config.fe 100 ptrType := fe.TypeBytePtr() 101 lenType := fe.TypeInt() 102 103 ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) 104 len := v.Block.NewValue0(v.Line, OpPhi, lenType) 105 for _, a := range v.Args { 106 ptr.AddArg(a.Block.NewValue1(v.Line, OpStringPtr, ptrType, a)) 107 len.AddArg(a.Block.NewValue1(v.Line, OpStringLen, lenType, a)) 108 } 109 v.reset(OpStringMake) 110 v.AddArg(ptr) 111 v.AddArg(len) 112 } 113 114 func decomposeSlicePhi(v *Value) { 115 fe := v.Block.Func.Config.fe 116 ptrType := fe.TypeBytePtr() 117 lenType := fe.TypeInt() 118 119 ptr := v.Block.NewValue0(v.Line, OpPhi, ptrType) 120 len := v.Block.NewValue0(v.Line, OpPhi, lenType) 121 cap := v.Block.NewValue0(v.Line, OpPhi, lenType) 122 for _, a := range v.Args { 123 ptr.AddArg(a.Block.NewValue1(v.Line, OpSlicePtr, ptrType, a)) 124 len.AddArg(a.Block.NewValue1(v.Line, OpSliceLen, lenType, a)) 125 cap.AddArg(a.Block.NewValue1(v.Line, OpSliceCap, lenType, a)) 126 } 127 v.reset(OpSliceMake) 128 v.AddArg(ptr) 129 v.AddArg(len) 130 v.AddArg(cap) 131 } 132 133 func decomposeComplexPhi(v *Value) { 134 fe := v.Block.Func.Config.fe 135 var partType Type 136 switch z := v.Type.Size(); z { 137 case 8: 138 partType = fe.TypeFloat32() 139 case 16: 140 partType = fe.TypeFloat64() 141 default: 142 v.Fatalf("decomposeComplexPhi: bad complex size %d", z) 143 } 144 145 real := v.Block.NewValue0(v.Line, OpPhi, partType) 146 imag := v.Block.NewValue0(v.Line, OpPhi, partType) 147 for _, a := range v.Args { 148 real.AddArg(a.Block.NewValue1(v.Line, OpComplexReal, partType, a)) 149 imag.AddArg(a.Block.NewValue1(v.Line, OpComplexImag, partType, a)) 150 } 151 v.reset(OpComplexMake) 152 v.AddArg(real) 153 v.AddArg(imag) 154 } 155 156 func decomposeInterfacePhi(v *Value) { 157 ptrType := v.Block.Func.Config.fe.TypeBytePtr() 158 159 itab := v.Block.NewValue0(v.Line, OpPhi, ptrType) 160 data := v.Block.NewValue0(v.Line, OpPhi, ptrType) 161 for _, a := range v.Args { 162 itab.AddArg(a.Block.NewValue1(v.Line, OpITab, ptrType, a)) 163 data.AddArg(a.Block.NewValue1(v.Line, OpIData, ptrType, a)) 164 } 165 v.reset(OpIMake) 166 v.AddArg(itab) 167 v.AddArg(data) 168 } 169 170 func decomposeUser(f *Func) { 171 for _, b := range f.Blocks { 172 for _, v := range b.Values { 173 if v.Op != OpPhi { 174 continue 175 } 176 decomposeUserPhi(v) 177 } 178 } 179 // Split up named values into their components. 180 // NOTE: the component values we are making are dead at this point. 181 // We must do the opt pass before any deadcode elimination or we will 182 // lose the name->value correspondence. 183 i := 0 184 for _, name := range f.Names { 185 t := name.Type 186 switch { 187 case t.IsStruct(): 188 n := t.NumFields() 189 for _, v := range f.NamedValues[name] { 190 for i := 0; i < n; i++ { 191 fname := LocalSlot{name.N, t.FieldType(i), name.Off + t.FieldOff(i)} // TODO: use actual field name? 192 x := v.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), v) 193 f.NamedValues[fname] = append(f.NamedValues[fname], x) 194 } 195 } 196 delete(f.NamedValues, name) 197 default: 198 f.Names[i] = name 199 i++ 200 } 201 } 202 f.Names = f.Names[:i] 203 } 204 205 func decomposeUserPhi(v *Value) { 206 switch { 207 case v.Type.IsStruct(): 208 decomposeStructPhi(v) 209 } 210 // TODO: Arrays of length 1? 211 } 212 213 func decomposeStructPhi(v *Value) { 214 t := v.Type 215 n := t.NumFields() 216 var fields [MaxStruct]*Value 217 for i := 0; i < n; i++ { 218 fields[i] = v.Block.NewValue0(v.Line, OpPhi, t.FieldType(i)) 219 } 220 for _, a := range v.Args { 221 for i := 0; i < n; i++ { 222 fields[i].AddArg(a.Block.NewValue1I(v.Line, OpStructSelect, t.FieldType(i), int64(i), a)) 223 } 224 } 225 v.reset(StructMakeOp(n)) 226 v.AddArgs(fields[:n]...) 227 228 // Recursively decompose phis for each field. 229 for _, f := range fields[:n] { 230 if f.Type.IsStruct() { 231 decomposeStructPhi(f) 232 } 233 } 234 } 235 236 // MaxStruct is the maximum number of fields a struct 237 // can have and still be SSAable. 238 const MaxStruct = 4 239 240 // StructMakeOp returns the opcode to construct a struct with the 241 // given number of fields. 242 func StructMakeOp(nf int) Op { 243 switch nf { 244 case 0: 245 return OpStructMake0 246 case 1: 247 return OpStructMake1 248 case 2: 249 return OpStructMake2 250 case 3: 251 return OpStructMake3 252 case 4: 253 return OpStructMake4 254 } 255 panic("too many fields in an SSAable struct") 256 }