github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ssa/emit.go (about) 1 // Copyright 2013 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 // Helpers for emitting SSA instructions. 8 9 import ( 10 "fmt" 11 "go/ast" 12 "go/token" 13 "go/types" 14 ) 15 16 // emitNew emits to f a new (heap Alloc) instruction allocating an 17 // object of type typ. pos is the optional source location. 18 // 19 func emitNew(f *Function, typ types.Type, pos token.Pos) *Alloc { 20 v := &Alloc{Heap: true} 21 v.setType(types.NewPointer(typ)) 22 v.setPos(pos) 23 f.emit(v) 24 return v 25 } 26 27 // emitLoad emits to f an instruction to load the address addr into a 28 // new temporary, and returns the value so defined. 29 // 30 func emitLoad(f *Function, addr Value) *UnOp { 31 v := &UnOp{Op: token.MUL, X: addr} 32 v.setType(deref(addr.Type())) 33 f.emit(v) 34 return v 35 } 36 37 // emitDebugRef emits to f a DebugRef pseudo-instruction associating 38 // expression e with value v. 39 // 40 func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) { 41 if !f.debugInfo() { 42 return // debugging not enabled 43 } 44 if v == nil || e == nil { 45 panic("nil") 46 } 47 var obj types.Object 48 e = unparen(e) 49 if id, ok := e.(*ast.Ident); ok { 50 if isBlankIdent(id) { 51 return 52 } 53 obj = f.objectOf(id) 54 switch obj.(type) { 55 case *types.Nil, *types.Const, *types.Builtin: 56 return 57 } 58 } 59 f.emit(&DebugRef{ 60 X: v, 61 Expr: e, 62 IsAddr: isAddr, 63 object: obj, 64 }) 65 } 66 67 // emitArith emits to f code to compute the binary operation op(x, y) 68 // where op is an eager shift, logical or arithmetic operation. 69 // (Use emitCompare() for comparisons and Builder.logicalBinop() for 70 // non-eager operations.) 71 // 72 func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.Pos) Value { 73 switch op { 74 case token.SHL, token.SHR: 75 x = emitConv(f, x, t) 76 // y may be signed or an 'untyped' constant. 77 78 // There is a runtime panic if y is signed and <0. Instead of inserting a check for y<0 79 // and converting to an unsigned value (like the compiler) leave y as is. 80 81 if isUntyped(y.Type().Underlying()) { 82 // Untyped conversion: 83 // Spec https://go.dev/ref/spec#Operators: 84 // The right operand in a shift expression must have integer type or be an untyped constant 85 // representable by a value of type uint. 86 y = emitConv(f, y, types.Typ[types.Uint]) 87 } 88 89 case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: 90 x = emitConv(f, x, t) 91 y = emitConv(f, y, t) 92 93 default: 94 panic("illegal op in emitArith: " + op.String()) 95 96 } 97 v := &BinOp{ 98 Op: op, 99 X: x, 100 Y: y, 101 } 102 v.setPos(pos) 103 v.setType(t) 104 return f.emit(v) 105 } 106 107 // emitCompare emits to f code compute the boolean result of 108 // comparison comparison 'x op y'. 109 // 110 func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value { 111 xt := x.Type().Underlying() 112 yt := y.Type().Underlying() 113 114 // Special case to optimise a tagless SwitchStmt so that 115 // these are equivalent 116 // switch { case e: ...} 117 // switch true { case e: ... } 118 // if e==true { ... } 119 // even in the case when e's type is an interface. 120 // TODO(adonovan): opt: generalise to x==true, false!=y, etc. 121 if x == vTrue && op == token.EQL { 122 if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 { 123 return y 124 } 125 } 126 127 if types.Identical(xt, yt) { 128 // no conversion necessary 129 } else if _, ok := xt.(*types.Interface); ok { 130 y = emitConv(f, y, x.Type()) 131 } else if _, ok := yt.(*types.Interface); ok { 132 x = emitConv(f, x, y.Type()) 133 } else if _, ok := x.(*Const); ok { 134 x = emitConv(f, x, y.Type()) 135 } else if _, ok := y.(*Const); ok { 136 y = emitConv(f, y, x.Type()) 137 } else { 138 // other cases, e.g. channels. No-op. 139 } 140 141 v := &BinOp{ 142 Op: op, 143 X: x, 144 Y: y, 145 } 146 v.setPos(pos) 147 v.setType(tBool) 148 return f.emit(v) 149 } 150 151 // isValuePreserving returns true if a conversion from ut_src to 152 // ut_dst is value-preserving, i.e. just a change of type. 153 // Precondition: neither argument is a named type. 154 // 155 func isValuePreserving(ut_src, ut_dst types.Type) bool { 156 // Identical underlying types? 157 if structTypesIdentical(ut_dst, ut_src) { 158 return true 159 } 160 161 switch ut_dst.(type) { 162 case *types.Chan: 163 // Conversion between channel types? 164 _, ok := ut_src.(*types.Chan) 165 return ok 166 167 case *types.Pointer: 168 // Conversion between pointers with identical base types? 169 _, ok := ut_src.(*types.Pointer) 170 return ok 171 } 172 return false 173 } 174 175 // emitConv emits to f code to convert Value val to exactly type typ, 176 // and returns the converted value. Implicit conversions are required 177 // by language assignability rules in assignments, parameter passing, 178 // etc. 179 // 180 func emitConv(f *Function, val Value, typ types.Type) Value { 181 t_src := val.Type() 182 183 // Identical types? Conversion is a no-op. 184 if types.Identical(t_src, typ) { 185 return val 186 } 187 188 ut_dst := typ.Underlying() 189 ut_src := t_src.Underlying() 190 191 // Just a change of type, but not value or representation? 192 if isValuePreserving(ut_src, ut_dst) { 193 c := &ChangeType{X: val} 194 c.setType(typ) 195 return f.emit(c) 196 } 197 198 // Conversion to, or construction of a value of, an interface type? 199 if _, ok := ut_dst.(*types.Interface); ok { 200 // Assignment from one interface type to another? 201 if _, ok := ut_src.(*types.Interface); ok { 202 c := &ChangeInterface{X: val} 203 c.setType(typ) 204 return f.emit(c) 205 } 206 207 // Untyped nil constant? Return interface-typed nil constant. 208 if ut_src == tUntypedNil { 209 return nilConst(typ) 210 } 211 212 // Convert (non-nil) "untyped" literals to their default type. 213 if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 { 214 val = emitConv(f, val, types.Default(ut_src)) 215 } 216 217 mi := &MakeInterface{X: val} 218 mi.setType(typ) 219 return f.emit(mi) 220 } 221 222 // Conversion of a compile-time constant value? 223 if c, ok := val.(*Const); ok { 224 if _, ok := ut_dst.(*types.Basic); ok || c.IsNil() { 225 // Conversion of a compile-time constant to 226 // another constant type results in a new 227 // constant of the destination type and 228 // (initially) the same abstract value. 229 // We don't truncate the value yet. 230 return NewConst(c.Value, typ) 231 } 232 233 // We're converting from constant to non-constant type, 234 // e.g. string -> []byte/[]rune. 235 } 236 237 // Conversion from slice to array pointer? 238 if slice, ok := ut_src.(*types.Slice); ok { 239 if ptr, ok := ut_dst.(*types.Pointer); ok { 240 if arr, ok := ptr.Elem().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) { 241 c := &SliceToArrayPointer{X: val} 242 c.setType(ut_dst) 243 return f.emit(c) 244 } 245 } 246 } 247 // A representation-changing conversion? 248 // At least one of {ut_src,ut_dst} must be *Basic. 249 // (The other may be []byte or []rune.) 250 _, ok1 := ut_src.(*types.Basic) 251 _, ok2 := ut_dst.(*types.Basic) 252 if ok1 || ok2 { 253 c := &Convert{X: val} 254 c.setType(typ) 255 return f.emit(c) 256 } 257 258 panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ)) 259 } 260 261 // emitStore emits to f an instruction to store value val at location 262 // addr, applying implicit conversions as required by assignability rules. 263 // 264 func emitStore(f *Function, addr, val Value, pos token.Pos) *Store { 265 s := &Store{ 266 Addr: addr, 267 Val: emitConv(f, val, deref(addr.Type())), 268 pos: pos, 269 } 270 f.emit(s) 271 return s 272 } 273 274 // emitJump emits to f a jump to target, and updates the control-flow graph. 275 // Postcondition: f.currentBlock is nil. 276 // 277 func emitJump(f *Function, target *BasicBlock) { 278 b := f.currentBlock 279 b.emit(new(Jump)) 280 addEdge(b, target) 281 f.currentBlock = nil 282 } 283 284 // emitIf emits to f a conditional jump to tblock or fblock based on 285 // cond, and updates the control-flow graph. 286 // Postcondition: f.currentBlock is nil. 287 // 288 func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) { 289 b := f.currentBlock 290 b.emit(&If{Cond: cond}) 291 addEdge(b, tblock) 292 addEdge(b, fblock) 293 f.currentBlock = nil 294 } 295 296 // emitExtract emits to f an instruction to extract the index'th 297 // component of tuple. It returns the extracted value. 298 // 299 func emitExtract(f *Function, tuple Value, index int) Value { 300 e := &Extract{Tuple: tuple, Index: index} 301 e.setType(tuple.Type().(*types.Tuple).At(index).Type()) 302 return f.emit(e) 303 } 304 305 // emitTypeAssert emits to f a type assertion value := x.(t) and 306 // returns the value. x.Type() must be an interface. 307 // 308 func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value { 309 a := &TypeAssert{X: x, AssertedType: t} 310 a.setPos(pos) 311 a.setType(t) 312 return f.emit(a) 313 } 314 315 // emitTypeTest emits to f a type test value,ok := x.(t) and returns 316 // a (value, ok) tuple. x.Type() must be an interface. 317 // 318 func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value { 319 a := &TypeAssert{ 320 X: x, 321 AssertedType: t, 322 CommaOk: true, 323 } 324 a.setPos(pos) 325 a.setType(types.NewTuple( 326 newVar("value", t), 327 varOk, 328 )) 329 return f.emit(a) 330 } 331 332 // emitTailCall emits to f a function call in tail position. The 333 // caller is responsible for all fields of 'call' except its type. 334 // Intended for wrapper methods. 335 // Precondition: f does/will not use deferred procedure calls. 336 // Postcondition: f.currentBlock is nil. 337 // 338 func emitTailCall(f *Function, call *Call) { 339 tresults := f.Signature.Results() 340 nr := tresults.Len() 341 if nr == 1 { 342 call.typ = tresults.At(0).Type() 343 } else { 344 call.typ = tresults 345 } 346 tuple := f.emit(call) 347 var ret Return 348 switch nr { 349 case 0: 350 // no-op 351 case 1: 352 ret.Results = []Value{tuple} 353 default: 354 for i := 0; i < nr; i++ { 355 v := emitExtract(f, tuple, i) 356 // TODO(adonovan): in principle, this is required: 357 // v = emitConv(f, o.Type, f.Signature.Results[i].Type) 358 // but in practice emitTailCall is only used when 359 // the types exactly match. 360 ret.Results = append(ret.Results, v) 361 } 362 } 363 f.emit(&ret) 364 f.currentBlock = nil 365 } 366 367 // emitImplicitSelections emits to f code to apply the sequence of 368 // implicit field selections specified by indices to base value v, and 369 // returns the selected value. 370 // 371 // If v is the address of a struct, the result will be the address of 372 // a field; if it is the value of a struct, the result will be the 373 // value of a field. 374 // 375 func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) Value { 376 for _, index := range indices { 377 fld := deref(v.Type()).Underlying().(*types.Struct).Field(index) 378 379 if isPointer(v.Type()) { 380 instr := &FieldAddr{ 381 X: v, 382 Field: index, 383 } 384 instr.setPos(pos) 385 instr.setType(types.NewPointer(fld.Type())) 386 v = f.emit(instr) 387 // Load the field's value iff indirectly embedded. 388 if isPointer(fld.Type()) { 389 v = emitLoad(f, v) 390 } 391 } else { 392 instr := &Field{ 393 X: v, 394 Field: index, 395 } 396 instr.setPos(pos) 397 instr.setType(fld.Type()) 398 v = f.emit(instr) 399 } 400 } 401 return v 402 } 403 404 // emitFieldSelection emits to f code to select the index'th field of v. 405 // 406 // If wantAddr, the input must be a pointer-to-struct and the result 407 // will be the field's address; otherwise the result will be the 408 // field's value. 409 // Ident id is used for position and debug info. 410 // 411 func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value { 412 fld := deref(v.Type()).Underlying().(*types.Struct).Field(index) 413 if isPointer(v.Type()) { 414 instr := &FieldAddr{ 415 X: v, 416 Field: index, 417 } 418 instr.setPos(id.Pos()) 419 instr.setType(types.NewPointer(fld.Type())) 420 v = f.emit(instr) 421 // Load the field's value iff we don't want its address. 422 if !wantAddr { 423 v = emitLoad(f, v) 424 } 425 } else { 426 instr := &Field{ 427 X: v, 428 Field: index, 429 } 430 instr.setPos(id.Pos()) 431 instr.setType(fld.Type()) 432 v = f.emit(instr) 433 } 434 emitDebugRef(f, id, v, wantAddr) 435 return v 436 } 437 438 // zeroValue emits to f code to produce a zero value of type t, 439 // and returns it. 440 // 441 func zeroValue(f *Function, t types.Type) Value { 442 switch t.Underlying().(type) { 443 case *types.Struct, *types.Array: 444 return emitLoad(f, f.addLocal(t, token.NoPos)) 445 default: 446 return zeroConst(t) 447 } 448 } 449 450 // createRecoverBlock emits to f a block of code to return after a 451 // recovered panic, and sets f.Recover to it. 452 // 453 // If f's result parameters are named, the code loads and returns 454 // their current values, otherwise it returns the zero values of their 455 // type. 456 // 457 // Idempotent. 458 // 459 func createRecoverBlock(f *Function) { 460 if f.Recover != nil { 461 return // already created 462 } 463 saved := f.currentBlock 464 465 f.Recover = f.newBasicBlock("recover") 466 f.currentBlock = f.Recover 467 468 var results []Value 469 if f.namedResults != nil { 470 // Reload NRPs to form value tuple. 471 for _, r := range f.namedResults { 472 results = append(results, emitLoad(f, r)) 473 } 474 } else { 475 R := f.Signature.Results() 476 for i, n := 0, R.Len(); i < n; i++ { 477 T := R.At(i).Type() 478 479 // Return zero value of each result type. 480 results = append(results, zeroValue(f, T)) 481 } 482 } 483 f.emit(&Return{Results: results}) 484 485 f.currentBlock = saved 486 }