golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/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 "golang.org/x/tools/internal/typeparams" 16 ) 17 18 // emitAlloc emits to f a new Alloc instruction allocating a variable 19 // of type typ. 20 // 21 // The caller must set Alloc.Heap=true (for an heap-allocated variable) 22 // or add the Alloc to f.Locals (for a frame-allocated variable). 23 // 24 // During building, a variable in f.Locals may have its Heap flag 25 // set when it is discovered that its address is taken. 26 // These Allocs are removed from f.Locals at the end. 27 // 28 // The builder should generally call one of the emit{New,Local,LocalVar} wrappers instead. 29 func emitAlloc(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { 30 v := &Alloc{Comment: comment} 31 v.setType(types.NewPointer(typ)) 32 v.setPos(pos) 33 f.emit(v) 34 return v 35 } 36 37 // emitNew emits to f a new Alloc instruction heap-allocating a 38 // variable of type typ. pos is the optional source location. 39 func emitNew(f *Function, typ types.Type, pos token.Pos, comment string) *Alloc { 40 alloc := emitAlloc(f, typ, pos, comment) 41 alloc.Heap = true 42 return alloc 43 } 44 45 // emitLocal creates a local var for (t, pos, comment) and 46 // emits an Alloc instruction for it. 47 // 48 // (Use this function or emitNew for synthetic variables; 49 // for source-level variables in the same function, use emitLocalVar.) 50 func emitLocal(f *Function, t types.Type, pos token.Pos, comment string) *Alloc { 51 local := emitAlloc(f, t, pos, comment) 52 f.Locals = append(f.Locals, local) 53 return local 54 } 55 56 // emitLocalVar creates a local var for v and emits an Alloc instruction for it. 57 // Subsequent calls to f.lookup(v) return it. 58 // It applies the appropriate generic instantiation to the type. 59 func emitLocalVar(f *Function, v *types.Var) *Alloc { 60 alloc := emitLocal(f, f.typ(v.Type()), v.Pos(), v.Name()) 61 f.vars[v] = alloc 62 return alloc 63 } 64 65 // emitLoad emits to f an instruction to load the address addr into a 66 // new temporary, and returns the value so defined. 67 func emitLoad(f *Function, addr Value) *UnOp { 68 v := &UnOp{Op: token.MUL, X: addr} 69 v.setType(typeparams.MustDeref(addr.Type())) 70 f.emit(v) 71 return v 72 } 73 74 // emitDebugRef emits to f a DebugRef pseudo-instruction associating 75 // expression e with value v. 76 func emitDebugRef(f *Function, e ast.Expr, v Value, isAddr bool) { 77 if !f.debugInfo() { 78 return // debugging not enabled 79 } 80 if v == nil || e == nil { 81 panic("nil") 82 } 83 var obj types.Object 84 e = unparen(e) 85 if id, ok := e.(*ast.Ident); ok { 86 if isBlankIdent(id) { 87 return 88 } 89 obj = f.objectOf(id) 90 switch obj.(type) { 91 case *types.Nil, *types.Const, *types.Builtin: 92 return 93 } 94 } 95 f.emit(&DebugRef{ 96 X: v, 97 Expr: e, 98 IsAddr: isAddr, 99 object: obj, 100 }) 101 } 102 103 // emitArith emits to f code to compute the binary operation op(x, y) 104 // where op is an eager shift, logical or arithmetic operation. 105 // (Use emitCompare() for comparisons and Builder.logicalBinop() for 106 // non-eager operations.) 107 func emitArith(f *Function, op token.Token, x, y Value, t types.Type, pos token.Pos) Value { 108 switch op { 109 case token.SHL, token.SHR: 110 x = emitConv(f, x, t) 111 // y may be signed or an 'untyped' constant. 112 113 // There is a runtime panic if y is signed and <0. Instead of inserting a check for y<0 114 // and converting to an unsigned value (like the compiler) leave y as is. 115 116 if isUntyped(y.Type().Underlying()) { 117 // Untyped conversion: 118 // Spec https://go.dev/ref/spec#Operators: 119 // The right operand in a shift expression must have integer type or be an untyped constant 120 // representable by a value of type uint. 121 y = emitConv(f, y, types.Typ[types.Uint]) 122 } 123 124 case token.ADD, token.SUB, token.MUL, token.QUO, token.REM, token.AND, token.OR, token.XOR, token.AND_NOT: 125 x = emitConv(f, x, t) 126 y = emitConv(f, y, t) 127 128 default: 129 panic("illegal op in emitArith: " + op.String()) 130 131 } 132 v := &BinOp{ 133 Op: op, 134 X: x, 135 Y: y, 136 } 137 v.setPos(pos) 138 v.setType(t) 139 return f.emit(v) 140 } 141 142 // emitCompare emits to f code compute the boolean result of 143 // comparison 'x op y'. 144 func emitCompare(f *Function, op token.Token, x, y Value, pos token.Pos) Value { 145 xt := x.Type().Underlying() 146 yt := y.Type().Underlying() 147 148 // Special case to optimise a tagless SwitchStmt so that 149 // these are equivalent 150 // switch { case e: ...} 151 // switch true { case e: ... } 152 // if e==true { ... } 153 // even in the case when e's type is an interface. 154 // TODO(adonovan): opt: generalise to x==true, false!=y, etc. 155 if x == vTrue && op == token.EQL { 156 if yt, ok := yt.(*types.Basic); ok && yt.Info()&types.IsBoolean != 0 { 157 return y 158 } 159 } 160 161 if types.Identical(xt, yt) { 162 // no conversion necessary 163 } else if isNonTypeParamInterface(x.Type()) { 164 y = emitConv(f, y, x.Type()) 165 } else if isNonTypeParamInterface(y.Type()) { 166 x = emitConv(f, x, y.Type()) 167 } else if _, ok := x.(*Const); ok { 168 x = emitConv(f, x, y.Type()) 169 } else if _, ok := y.(*Const); ok { 170 y = emitConv(f, y, x.Type()) 171 } else { 172 // other cases, e.g. channels. No-op. 173 } 174 175 v := &BinOp{ 176 Op: op, 177 X: x, 178 Y: y, 179 } 180 v.setPos(pos) 181 v.setType(tBool) 182 return f.emit(v) 183 } 184 185 // isValuePreserving returns true if a conversion from ut_src to 186 // ut_dst is value-preserving, i.e. just a change of type. 187 // Precondition: neither argument is a named or alias type. 188 func isValuePreserving(ut_src, ut_dst types.Type) bool { 189 // Identical underlying types? 190 if types.IdenticalIgnoreTags(ut_dst, ut_src) { 191 return true 192 } 193 194 switch ut_dst.(type) { 195 case *types.Chan: 196 // Conversion between channel types? 197 _, ok := ut_src.(*types.Chan) 198 return ok 199 200 case *types.Pointer: 201 // Conversion between pointers with identical base types? 202 _, ok := ut_src.(*types.Pointer) 203 return ok 204 } 205 return false 206 } 207 208 // emitConv emits to f code to convert Value val to exactly type typ, 209 // and returns the converted value. Implicit conversions are required 210 // by language assignability rules in assignments, parameter passing, 211 // etc. 212 func emitConv(f *Function, val Value, typ types.Type) Value { 213 t_src := val.Type() 214 215 // Identical types? Conversion is a no-op. 216 if types.Identical(t_src, typ) { 217 return val 218 } 219 ut_dst := typ.Underlying() 220 ut_src := t_src.Underlying() 221 222 // Conversion to, or construction of a value of, an interface type? 223 if isNonTypeParamInterface(typ) { 224 // Interface name change? 225 if isValuePreserving(ut_src, ut_dst) { 226 c := &ChangeType{X: val} 227 c.setType(typ) 228 return f.emit(c) 229 } 230 231 // Assignment from one interface type to another? 232 if isNonTypeParamInterface(t_src) { 233 c := &ChangeInterface{X: val} 234 c.setType(typ) 235 return f.emit(c) 236 } 237 238 // Untyped nil constant? Return interface-typed nil constant. 239 if ut_src == tUntypedNil { 240 return zeroConst(typ) 241 } 242 243 // Convert (non-nil) "untyped" literals to their default type. 244 if t, ok := ut_src.(*types.Basic); ok && t.Info()&types.IsUntyped != 0 { 245 val = emitConv(f, val, types.Default(ut_src)) 246 } 247 248 // Record the types of operands to MakeInterface, if 249 // non-parameterized, as they are the set of runtime types. 250 t := val.Type() 251 if f.typeparams.Len() == 0 || !f.Prog.isParameterized(t) { 252 addRuntimeType(f.Prog, t) 253 } 254 255 mi := &MakeInterface{X: val} 256 mi.setType(typ) 257 return f.emit(mi) 258 } 259 260 // In the common case, the typesets of src and dst are singletons 261 // and we emit an appropriate conversion. But if either contains 262 // a type parameter, the conversion may represent a cross product, 263 // in which case which we emit a MultiConvert. 264 dst_terms := typeSetOf(ut_dst) 265 src_terms := typeSetOf(ut_src) 266 267 // conversionCase describes an instruction pattern that maybe emitted to 268 // model d <- s for d in dst_terms and s in src_terms. 269 // Multiple conversions can match the same pattern. 270 type conversionCase uint8 271 const ( 272 changeType conversionCase = 1 << iota 273 sliceToArray 274 sliceToArrayPtr 275 sliceTo0Array 276 sliceTo0ArrayPtr 277 convert 278 ) 279 // classify the conversion case of a source type us to a destination type ud. 280 // us and ud are underlying types (not *Named or *Alias) 281 classify := func(us, ud types.Type) conversionCase { 282 // Just a change of type, but not value or representation? 283 if isValuePreserving(us, ud) { 284 return changeType 285 } 286 287 // Conversion from slice to array or slice to array pointer? 288 if slice, ok := us.(*types.Slice); ok { 289 var arr *types.Array 290 var ptr bool 291 // Conversion from slice to array pointer? 292 switch d := ud.(type) { 293 case *types.Array: 294 arr = d 295 case *types.Pointer: 296 arr, _ = d.Elem().Underlying().(*types.Array) 297 ptr = true 298 } 299 if arr != nil && types.Identical(slice.Elem(), arr.Elem()) { 300 if arr.Len() == 0 { 301 if ptr { 302 return sliceTo0ArrayPtr 303 } else { 304 return sliceTo0Array 305 } 306 } 307 if ptr { 308 return sliceToArrayPtr 309 } else { 310 return sliceToArray 311 } 312 } 313 } 314 315 // The only remaining case in well-typed code is a representation- 316 // changing conversion of basic types (possibly with []byte/[]rune). 317 if !isBasic(us) && !isBasic(ud) { 318 panic(fmt.Sprintf("in %s: cannot convert term %s (%s [within %s]) to type %s [within %s]", f, val, val.Type(), us, typ, ud)) 319 } 320 return convert 321 } 322 323 var classifications conversionCase 324 for _, s := range src_terms { 325 us := s.Type().Underlying() 326 for _, d := range dst_terms { 327 ud := d.Type().Underlying() 328 classifications |= classify(us, ud) 329 } 330 } 331 if classifications == 0 { 332 panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ)) 333 } 334 335 // Conversion of a compile-time constant value? 336 if c, ok := val.(*Const); ok { 337 // Conversion to a basic type? 338 if isBasic(ut_dst) { 339 // Conversion of a compile-time constant to 340 // another constant type results in a new 341 // constant of the destination type and 342 // (initially) the same abstract value. 343 // We don't truncate the value yet. 344 return NewConst(c.Value, typ) 345 } 346 // Can we always convert from zero value without panicking? 347 const mayPanic = sliceToArray | sliceToArrayPtr 348 if c.Value == nil && classifications&mayPanic == 0 { 349 return NewConst(nil, typ) 350 } 351 352 // We're converting from constant to non-constant type, 353 // e.g. string -> []byte/[]rune. 354 } 355 356 switch classifications { 357 case changeType: // representation-preserving change 358 c := &ChangeType{X: val} 359 c.setType(typ) 360 return f.emit(c) 361 362 case sliceToArrayPtr, sliceTo0ArrayPtr: // slice to array pointer 363 c := &SliceToArrayPointer{X: val} 364 c.setType(typ) 365 return f.emit(c) 366 367 case sliceToArray: // slice to arrays (not zero-length) 368 ptype := types.NewPointer(typ) 369 p := &SliceToArrayPointer{X: val} 370 p.setType(ptype) 371 x := f.emit(p) 372 unOp := &UnOp{Op: token.MUL, X: x} 373 unOp.setType(typ) 374 return f.emit(unOp) 375 376 case sliceTo0Array: // slice to zero-length arrays (constant) 377 return zeroConst(typ) 378 379 case convert: // representation-changing conversion 380 c := &Convert{X: val} 381 c.setType(typ) 382 return f.emit(c) 383 384 default: // multiple conversion 385 c := &MultiConvert{X: val, from: src_terms, to: dst_terms} 386 c.setType(typ) 387 return f.emit(c) 388 } 389 } 390 391 // emitTypeCoercion emits to f code to coerce the type of a 392 // Value v to exactly type typ, and returns the coerced value. 393 // 394 // Requires that coercing v.Typ() to typ is a value preserving change. 395 // 396 // Currently used only when v.Type() is a type instance of typ or vice versa. 397 // A type v is a type instance of a type t if there exists a 398 // type parameter substitution σ s.t. σ(v) == t. Example: 399 // 400 // σ(func(T) T) == func(int) int for σ == [T ↦ int] 401 // 402 // This happens in instantiation wrappers for conversion 403 // from an instantiation to a parameterized type (and vice versa) 404 // with σ substituting f.typeparams by f.typeargs. 405 func emitTypeCoercion(f *Function, v Value, typ types.Type) Value { 406 if types.Identical(v.Type(), typ) { 407 return v // no coercion needed 408 } 409 // TODO(taking): for instances should we record which side is the instance? 410 c := &ChangeType{ 411 X: v, 412 } 413 c.setType(typ) 414 f.emit(c) 415 return c 416 } 417 418 // emitStore emits to f an instruction to store value val at location 419 // addr, applying implicit conversions as required by assignability rules. 420 func emitStore(f *Function, addr, val Value, pos token.Pos) *Store { 421 typ := typeparams.MustDeref(addr.Type()) 422 s := &Store{ 423 Addr: addr, 424 Val: emitConv(f, val, typ), 425 pos: pos, 426 } 427 f.emit(s) 428 return s 429 } 430 431 // emitJump emits to f a jump to target, and updates the control-flow graph. 432 // Postcondition: f.currentBlock is nil. 433 func emitJump(f *Function, target *BasicBlock) { 434 b := f.currentBlock 435 b.emit(new(Jump)) 436 addEdge(b, target) 437 f.currentBlock = nil 438 } 439 440 // emitIf emits to f a conditional jump to tblock or fblock based on 441 // cond, and updates the control-flow graph. 442 // Postcondition: f.currentBlock is nil. 443 func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) { 444 b := f.currentBlock 445 b.emit(&If{Cond: cond}) 446 addEdge(b, tblock) 447 addEdge(b, fblock) 448 f.currentBlock = nil 449 } 450 451 // emitExtract emits to f an instruction to extract the index'th 452 // component of tuple. It returns the extracted value. 453 func emitExtract(f *Function, tuple Value, index int) Value { 454 e := &Extract{Tuple: tuple, Index: index} 455 e.setType(tuple.Type().(*types.Tuple).At(index).Type()) 456 return f.emit(e) 457 } 458 459 // emitTypeAssert emits to f a type assertion value := x.(t) and 460 // returns the value. x.Type() must be an interface. 461 func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value { 462 a := &TypeAssert{X: x, AssertedType: t} 463 a.setPos(pos) 464 a.setType(t) 465 return f.emit(a) 466 } 467 468 // emitTypeTest emits to f a type test value,ok := x.(t) and returns 469 // a (value, ok) tuple. x.Type() must be an interface. 470 func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value { 471 a := &TypeAssert{ 472 X: x, 473 AssertedType: t, 474 CommaOk: true, 475 } 476 a.setPos(pos) 477 a.setType(types.NewTuple( 478 newVar("value", t), 479 varOk, 480 )) 481 return f.emit(a) 482 } 483 484 // emitTailCall emits to f a function call in tail position. The 485 // caller is responsible for all fields of 'call' except its type. 486 // Intended for wrapper methods. 487 // Precondition: f does/will not use deferred procedure calls. 488 // Postcondition: f.currentBlock is nil. 489 func emitTailCall(f *Function, call *Call) { 490 tresults := f.Signature.Results() 491 nr := tresults.Len() 492 if nr == 1 { 493 call.typ = tresults.At(0).Type() 494 } else { 495 call.typ = tresults 496 } 497 tuple := f.emit(call) 498 var ret Return 499 switch nr { 500 case 0: 501 // no-op 502 case 1: 503 ret.Results = []Value{tuple} 504 default: 505 for i := 0; i < nr; i++ { 506 v := emitExtract(f, tuple, i) 507 // TODO(adonovan): in principle, this is required: 508 // v = emitConv(f, o.Type, f.Signature.Results[i].Type) 509 // but in practice emitTailCall is only used when 510 // the types exactly match. 511 ret.Results = append(ret.Results, v) 512 } 513 } 514 f.emit(&ret) 515 f.currentBlock = nil 516 } 517 518 // emitImplicitSelections emits to f code to apply the sequence of 519 // implicit field selections specified by indices to base value v, and 520 // returns the selected value. 521 // 522 // If v is the address of a struct, the result will be the address of 523 // a field; if it is the value of a struct, the result will be the 524 // value of a field. 525 func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) Value { 526 for _, index := range indices { 527 if isPointerCore(v.Type()) { 528 fld := fieldOf(typeparams.MustDeref(v.Type()), index) 529 instr := &FieldAddr{ 530 X: v, 531 Field: index, 532 } 533 instr.setPos(pos) 534 instr.setType(types.NewPointer(fld.Type())) 535 v = f.emit(instr) 536 // Load the field's value iff indirectly embedded. 537 if isPointerCore(fld.Type()) { 538 v = emitLoad(f, v) 539 } 540 } else { 541 fld := fieldOf(v.Type(), index) 542 instr := &Field{ 543 X: v, 544 Field: index, 545 } 546 instr.setPos(pos) 547 instr.setType(fld.Type()) 548 v = f.emit(instr) 549 } 550 } 551 return v 552 } 553 554 // emitFieldSelection emits to f code to select the index'th field of v. 555 // 556 // If wantAddr, the input must be a pointer-to-struct and the result 557 // will be the field's address; otherwise the result will be the 558 // field's value. 559 // Ident id is used for position and debug info. 560 func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value { 561 if isPointerCore(v.Type()) { 562 fld := fieldOf(typeparams.MustDeref(v.Type()), index) 563 instr := &FieldAddr{ 564 X: v, 565 Field: index, 566 } 567 instr.setPos(id.Pos()) 568 instr.setType(types.NewPointer(fld.Type())) 569 v = f.emit(instr) 570 // Load the field's value iff we don't want its address. 571 if !wantAddr { 572 v = emitLoad(f, v) 573 } 574 } else { 575 fld := fieldOf(v.Type(), index) 576 instr := &Field{ 577 X: v, 578 Field: index, 579 } 580 instr.setPos(id.Pos()) 581 instr.setType(fld.Type()) 582 v = f.emit(instr) 583 } 584 emitDebugRef(f, id, v, wantAddr) 585 return v 586 } 587 588 // createRecoverBlock emits to f a block of code to return after a 589 // recovered panic, and sets f.Recover to it. 590 // 591 // If f's result parameters are named, the code loads and returns 592 // their current values, otherwise it returns the zero values of their 593 // type. 594 // 595 // Idempotent. 596 func createRecoverBlock(f *Function) { 597 if f.Recover != nil { 598 return // already created 599 } 600 saved := f.currentBlock 601 602 f.Recover = f.newBasicBlock("recover") 603 f.currentBlock = f.Recover 604 605 var results []Value 606 // Reload NRPs to form value tuple. 607 for _, nr := range f.results { 608 results = append(results, emitLoad(f, nr)) 609 } 610 611 f.emit(&Return{Results: results}) 612 613 f.currentBlock = saved 614 }