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