emit.go (17788B)
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 a 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 = ast.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.Prog.isParameterized(t) { 252 addMakeInterfaceType(f.Prog, t) 253 } 254 255 mi := &MakeInterface{X: val} 256 mi.setType(typ) 257 return f.emit(mi) 258 } 259 260 // conversionCase describes an instruction pattern that maybe emitted to 261 // model d <- s for d in dst_terms and s in src_terms. 262 // Multiple conversions can match the same pattern. 263 type conversionCase uint8 264 const ( 265 changeType conversionCase = 1 << iota 266 sliceToArray 267 sliceToArrayPtr 268 sliceTo0Array 269 sliceTo0ArrayPtr 270 convert 271 ) 272 // classify the conversion case of a source type us to a destination type ud. 273 // us and ud are underlying types (not *Named or *Alias) 274 classify := func(us, ud types.Type) conversionCase { 275 // Just a change of type, but not value or representation? 276 if isValuePreserving(us, ud) { 277 return changeType 278 } 279 280 // Conversion from slice to array or slice to array pointer? 281 if slice, ok := us.(*types.Slice); ok { 282 var arr *types.Array 283 var ptr bool 284 // Conversion from slice to array pointer? 285 switch d := ud.(type) { 286 case *types.Array: 287 arr = d 288 case *types.Pointer: 289 arr, _ = d.Elem().Underlying().(*types.Array) 290 ptr = true 291 } 292 if arr != nil && types.Identical(slice.Elem(), arr.Elem()) { 293 if arr.Len() == 0 { 294 if ptr { 295 return sliceTo0ArrayPtr 296 } else { 297 return sliceTo0Array 298 } 299 } 300 if ptr { 301 return sliceToArrayPtr 302 } else { 303 return sliceToArray 304 } 305 } 306 } 307 308 // The only remaining case in well-typed code is a representation- 309 // changing conversion of basic types (possibly with []byte/[]rune). 310 if !isBasic(us) && !isBasic(ud) { 311 panic(fmt.Sprintf("in %s: cannot convert term %s (%s [within %s]) to type %s [within %s]", f, val, val.Type(), us, typ, ud)) 312 } 313 return convert 314 } 315 316 var classifications conversionCase 317 underIs(ut_src, func(us types.Type) bool { 318 return underIs(ut_dst, func(ud types.Type) bool { 319 if us != nil && ud != nil { 320 classifications |= classify(us, ud) 321 } 322 return classifications != 0 323 }) 324 }) 325 if classifications == 0 { 326 panic(fmt.Sprintf("in %s: cannot convert %s (%s) to %s", f, val, val.Type(), typ)) 327 } 328 329 // Conversion of a compile-time constant value? 330 if c, ok := val.(*Const); ok { 331 // Conversion to a basic type? 332 if isBasic(ut_dst) { 333 // Conversion of a compile-time constant to 334 // another constant type results in a new 335 // constant of the destination type and 336 // (initially) the same abstract value. 337 // We don't truncate the value yet. 338 return NewConst(c.Value, typ) 339 } 340 // Can we always convert from zero value without panicking? 341 const mayPanic = sliceToArray | sliceToArrayPtr 342 if c.Value == nil && classifications&mayPanic == 0 { 343 return NewConst(nil, typ) 344 } 345 346 // We're converting from constant to non-constant type, 347 // e.g. string -> []byte/[]rune. 348 } 349 350 switch classifications { 351 case changeType: // representation-preserving change 352 c := &ChangeType{X: val} 353 c.setType(typ) 354 return f.emit(c) 355 356 case sliceToArrayPtr, sliceTo0ArrayPtr: // slice to array pointer 357 c := &SliceToArrayPointer{X: val} 358 c.setType(typ) 359 return f.emit(c) 360 361 case sliceToArray: // slice to arrays (not zero-length) 362 ptype := types.NewPointer(typ) 363 p := &SliceToArrayPointer{X: val} 364 p.setType(ptype) 365 x := f.emit(p) 366 unOp := &UnOp{Op: token.MUL, X: x} 367 unOp.setType(typ) 368 return f.emit(unOp) 369 370 case sliceTo0Array: // slice to zero-length arrays (constant) 371 return zeroConst(typ) 372 373 case convert: // representation-changing conversion 374 c := &Convert{X: val} 375 c.setType(typ) 376 return f.emit(c) 377 378 default: // The conversion represents a cross product. 379 c := &MultiConvert{X: val, from: t_src, to: typ} 380 c.setType(typ) 381 return f.emit(c) 382 } 383 } 384 385 // emitTypeCoercion emits to f code to coerce the type of a 386 // Value v to exactly type typ, and returns the coerced value. 387 // 388 // Requires that coercing v.Typ() to typ is a value preserving change. 389 // 390 // Currently used only when v.Type() is a type instance of typ or vice versa. 391 // A type v is a type instance of a type t if there exists a 392 // type parameter substitution σ s.t. σ(v) == t. Example: 393 // 394 // σ(func(T) T) == func(int) int for σ == [T ↦ int] 395 // 396 // This happens in instantiation wrappers for conversion 397 // from an instantiation to a parameterized type (and vice versa) 398 // with σ substituting f.typeparams by f.typeargs. 399 func emitTypeCoercion(f *Function, v Value, typ types.Type) Value { 400 if types.Identical(v.Type(), typ) { 401 return v // no coercion needed 402 } 403 // TODO(taking): for instances should we record which side is the instance? 404 c := &ChangeType{ 405 X: v, 406 } 407 c.setType(typ) 408 f.emit(c) 409 return c 410 } 411 412 // emitStore emits to f an instruction to store value val at location 413 // addr, applying implicit conversions as required by assignability rules. 414 func emitStore(f *Function, addr, val Value, pos token.Pos) *Store { 415 typ := typeparams.MustDeref(addr.Type()) 416 s := &Store{ 417 Addr: addr, 418 Val: emitConv(f, val, typ), 419 pos: pos, 420 } 421 f.emit(s) 422 return s 423 } 424 425 // emitJump emits to f a jump to target, and updates the control-flow graph. 426 // Postcondition: f.currentBlock is nil. 427 func emitJump(f *Function, target *BasicBlock) { 428 b := f.currentBlock 429 b.emit(new(Jump)) 430 addEdge(b, target) 431 f.currentBlock = nil 432 } 433 434 // emitIf emits to f a conditional jump to tblock or fblock based on 435 // cond, and updates the control-flow graph. 436 // Postcondition: f.currentBlock is nil. 437 func emitIf(f *Function, cond Value, tblock, fblock *BasicBlock) { 438 b := f.currentBlock 439 b.emit(&If{Cond: cond}) 440 addEdge(b, tblock) 441 addEdge(b, fblock) 442 f.currentBlock = nil 443 } 444 445 // emitExtract emits to f an instruction to extract the index'th 446 // component of tuple. It returns the extracted value. 447 func emitExtract(f *Function, tuple Value, index int) Value { 448 e := &Extract{Tuple: tuple, Index: index} 449 e.setType(tuple.Type().(*types.Tuple).At(index).Type()) 450 return f.emit(e) 451 } 452 453 // emitTypeAssert emits to f a type assertion value := x.(t) and 454 // returns the value. x.Type() must be an interface. 455 func emitTypeAssert(f *Function, x Value, t types.Type, pos token.Pos) Value { 456 a := &TypeAssert{X: x, AssertedType: t} 457 a.setPos(pos) 458 a.setType(t) 459 return f.emit(a) 460 } 461 462 // emitTypeTest emits to f a type test value,ok := x.(t) and returns 463 // a (value, ok) tuple. x.Type() must be an interface. 464 func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value { 465 a := &TypeAssert{ 466 X: x, 467 AssertedType: t, 468 CommaOk: true, 469 } 470 a.setPos(pos) 471 a.setType(types.NewTuple( 472 newVar("value", t), 473 varOk, 474 )) 475 return f.emit(a) 476 } 477 478 // emitTailCall emits to f a function call in tail position. The 479 // caller is responsible for all fields of 'call' except its type. 480 // Intended for wrapper methods. 481 // Precondition: f does/will not use deferred procedure calls. 482 // Postcondition: f.currentBlock is nil. 483 func emitTailCall(f *Function, call *Call) { 484 tresults := f.Signature.Results() 485 nr := tresults.Len() 486 if nr == 1 { 487 call.typ = tresults.At(0).Type() 488 } else { 489 call.typ = tresults 490 } 491 tuple := emitCall(f, call) 492 var ret Return 493 switch nr { 494 case 0: 495 // no-op 496 case 1: 497 ret.Results = []Value{tuple} 498 default: 499 for i := range nr { 500 v := emitExtract(f, tuple, i) 501 // TODO(adonovan): in principle, this is required: 502 // v = emitConv(f, o.Type, f.Signature.Results[i].Type) 503 // but in practice emitTailCall is only used when 504 // the types exactly match. 505 ret.Results = append(ret.Results, v) 506 } 507 } 508 f.emit(&ret) 509 f.currentBlock = nil 510 } 511 512 // emitCall emits a call instruction. If the callee is "no return", 513 // it also emits a panic to eliminate infeasible CFG edges. 514 func emitCall(fn *Function, call *Call) Value { 515 res := fn.emit(call) 516 517 callee := call.Call.StaticCallee() 518 if callee != nil && 519 callee.object != nil && 520 fn.Prog.noReturn != nil && 521 fn.Prog.noReturn(callee.object) { 522 // Call cannot return. Insert a panic after it. 523 fn.emit(&Panic{ 524 X: emitConv(fn, vNoReturn, tEface), 525 pos: call.Pos(), 526 }) 527 fn.currentBlock = fn.newBasicBlock("unreachable.noreturn") 528 } 529 530 return res 531 } 532 533 // emitImplicitSelections emits to f code to apply the sequence of 534 // implicit field selections specified by indices to base value v, and 535 // returns the selected value. 536 // 537 // If v is the address of a struct, the result will be the address of 538 // a field; if it is the value of a struct, the result will be the 539 // value of a field. 540 func emitImplicitSelections(f *Function, v Value, indices []int, pos token.Pos) Value { 541 for _, index := range indices { 542 if isPointerCore(v.Type()) { 543 fld := fieldOf(typeparams.MustDeref(v.Type()), index) 544 instr := &FieldAddr{ 545 X: v, 546 Field: index, 547 } 548 instr.setPos(pos) 549 instr.setType(types.NewPointer(fld.Type())) 550 v = f.emit(instr) 551 // Load the field's value iff indirectly embedded. 552 if isPointerCore(fld.Type()) { 553 v = emitLoad(f, v) 554 } 555 } else { 556 fld := fieldOf(v.Type(), index) 557 instr := &Field{ 558 X: v, 559 Field: index, 560 } 561 instr.setPos(pos) 562 instr.setType(fld.Type()) 563 v = f.emit(instr) 564 } 565 } 566 return v 567 } 568 569 // emitFieldSelection emits to f code to select the index'th field of v. 570 // 571 // If wantAddr, the input must be a pointer-to-struct and the result 572 // will be the field's address; otherwise the result will be the 573 // field's value. 574 // Ident id is used for position and debug info. 575 func emitFieldSelection(f *Function, v Value, index int, wantAddr bool, id *ast.Ident) Value { 576 if isPointerCore(v.Type()) { 577 fld := fieldOf(typeparams.MustDeref(v.Type()), index) 578 instr := &FieldAddr{ 579 X: v, 580 Field: index, 581 } 582 instr.setPos(id.Pos()) 583 instr.setType(types.NewPointer(fld.Type())) 584 v = f.emit(instr) 585 // Load the field's value iff we don't want its address. 586 if !wantAddr { 587 v = emitLoad(f, v) 588 } 589 } else { 590 fld := fieldOf(v.Type(), index) 591 instr := &Field{ 592 X: v, 593 Field: index, 594 } 595 instr.setPos(id.Pos()) 596 instr.setType(fld.Type()) 597 v = f.emit(instr) 598 } 599 emitDebugRef(f, id, v, wantAddr) 600 return v 601 } 602 603 // createRecoverBlock emits to f a block of code to return after a 604 // recovered panic, and sets f.Recover to it. 605 // 606 // If f's result parameters are named, the code loads and returns 607 // their current values, otherwise it returns the zero values of their 608 // type. 609 // 610 // Idempotent. 611 func createRecoverBlock(f *Function) { 612 if f.Recover != nil { 613 return // already created 614 } 615 saved := f.currentBlock 616 617 f.Recover = f.newBasicBlock("recover") 618 f.currentBlock = f.Recover 619 620 var results []Value 621 // Reload NRPs to form value tuple. 622 for _, nr := range f.results { 623 results = append(results, emitLoad(f, nr)) 624 } 625 626 f.emit(&Return{Results: results}) 627 628 f.currentBlock = saved 629 }