github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/src/cmd/compile/internal/gc/ssa.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 gc 6 7 import ( 8 "bytes" 9 "encoding/binary" 10 "fmt" 11 "html" 12 "os" 13 "sort" 14 15 "cmd/compile/internal/ssa" 16 "cmd/compile/internal/types" 17 "cmd/internal/obj" 18 "cmd/internal/objabi" 19 "cmd/internal/src" 20 "cmd/internal/sys" 21 ) 22 23 var ssaConfig *ssa.Config 24 var ssaCaches []ssa.Cache 25 26 func initssaconfig() { 27 types_ := ssa.Types{ 28 Bool: types.Types[TBOOL], 29 Int8: types.Types[TINT8], 30 Int16: types.Types[TINT16], 31 Int32: types.Types[TINT32], 32 Int64: types.Types[TINT64], 33 UInt8: types.Types[TUINT8], 34 UInt16: types.Types[TUINT16], 35 UInt32: types.Types[TUINT32], 36 UInt64: types.Types[TUINT64], 37 Float32: types.Types[TFLOAT32], 38 Float64: types.Types[TFLOAT64], 39 Int: types.Types[TINT], 40 UInt: types.Types[TUINT], 41 Uintptr: types.Types[TUINTPTR], 42 String: types.Types[TSTRING], 43 BytePtr: types.NewPtr(types.Types[TUINT8]), 44 Int32Ptr: types.NewPtr(types.Types[TINT32]), 45 UInt32Ptr: types.NewPtr(types.Types[TUINT32]), 46 IntPtr: types.NewPtr(types.Types[TINT]), 47 UintptrPtr: types.NewPtr(types.Types[TUINTPTR]), 48 Float32Ptr: types.NewPtr(types.Types[TFLOAT32]), 49 Float64Ptr: types.NewPtr(types.Types[TFLOAT64]), 50 BytePtrPtr: types.NewPtr(types.NewPtr(types.Types[TUINT8])), 51 } 52 // Generate a few pointer types that are uncommon in the frontend but common in the backend. 53 // Caching is disabled in the backend, so generating these here avoids allocations. 54 _ = types.NewPtr(types.Types[TINTER]) // *interface{} 55 _ = types.NewPtr(types.NewPtr(types.Types[TSTRING])) // **string 56 _ = types.NewPtr(types.NewPtr(types.Idealstring)) // **string 57 _ = types.NewPtr(types.NewSlice(types.Types[TINTER])) // *[]interface{} 58 _ = types.NewPtr(types.NewPtr(types.Bytetype)) // **byte 59 _ = types.NewPtr(types.NewSlice(types.Bytetype)) // *[]byte 60 _ = types.NewPtr(types.NewSlice(types.Types[TSTRING])) // *[]string 61 _ = types.NewPtr(types.NewSlice(types.Idealstring)) // *[]string 62 _ = types.NewPtr(types.NewPtr(types.NewPtr(types.Types[TUINT8]))) // ***uint8 63 _ = types.NewPtr(types.Types[TINT16]) // *int16 64 _ = types.NewPtr(types.Types[TINT64]) // *int64 65 _ = types.NewPtr(types.Errortype) // *error 66 types.NewPtrCacheEnabled = false 67 ssaConfig = ssa.NewConfig(thearch.LinkArch.Name, types_, Ctxt, Debug['N'] == 0) 68 if thearch.LinkArch.Name == "386" { 69 ssaConfig.Set387(thearch.Use387) 70 } 71 ssaCaches = make([]ssa.Cache, nBackendWorkers) 72 73 // Set up some runtime functions we'll need to call. 74 Newproc = sysfunc("newproc") 75 Deferproc = sysfunc("deferproc") 76 Deferreturn = sysfunc("deferreturn") 77 Duffcopy = sysfunc("duffcopy") 78 Duffzero = sysfunc("duffzero") 79 panicindex = sysfunc("panicindex") 80 panicslice = sysfunc("panicslice") 81 panicdivide = sysfunc("panicdivide") 82 growslice = sysfunc("growslice") 83 panicdottypeE = sysfunc("panicdottypeE") 84 panicdottypeI = sysfunc("panicdottypeI") 85 panicnildottype = sysfunc("panicnildottype") 86 assertE2I = sysfunc("assertE2I") 87 assertE2I2 = sysfunc("assertE2I2") 88 assertI2I = sysfunc("assertI2I") 89 assertI2I2 = sysfunc("assertI2I2") 90 goschedguarded = sysfunc("goschedguarded") 91 writeBarrier = sysfunc("writeBarrier") 92 writebarrierptr = sysfunc("writebarrierptr") 93 typedmemmove = sysfunc("typedmemmove") 94 typedmemclr = sysfunc("typedmemclr") 95 Udiv = sysfunc("udiv") 96 97 // GO386=387 runtime functions 98 ControlWord64trunc = sysfunc("controlWord64trunc") 99 ControlWord32 = sysfunc("controlWord32") 100 } 101 102 // buildssa builds an SSA function for fn. 103 // worker indicates which of the backend workers is doing the processing. 104 func buildssa(fn *Node, worker int) *ssa.Func { 105 name := fn.funcname() 106 printssa := name == os.Getenv("GOSSAFUNC") 107 if printssa { 108 fmt.Println("generating SSA for", name) 109 dumplist("buildssa-enter", fn.Func.Enter) 110 dumplist("buildssa-body", fn.Nbody) 111 dumplist("buildssa-exit", fn.Func.Exit) 112 } 113 114 var s state 115 s.pushLine(fn.Pos) 116 defer s.popLine() 117 118 s.hasdefer = fn.Func.HasDefer() 119 if fn.Func.Pragma&CgoUnsafeArgs != 0 { 120 s.cgoUnsafeArgs = true 121 } 122 123 fe := ssafn{ 124 curfn: fn, 125 log: printssa, 126 } 127 s.curfn = fn 128 129 s.f = ssa.NewFunc(&fe) 130 s.config = ssaConfig 131 s.f.Config = ssaConfig 132 s.f.Cache = &ssaCaches[worker] 133 s.f.Cache.Reset() 134 s.f.DebugTest = s.f.DebugHashMatch("GOSSAHASH", name) 135 s.f.Name = name 136 if fn.Func.Pragma&Nosplit != 0 { 137 s.f.NoSplit = true 138 } 139 defer func() { 140 if s.f.WBPos.IsKnown() { 141 fn.Func.WBPos = s.f.WBPos 142 } 143 }() 144 s.exitCode = fn.Func.Exit 145 s.panics = map[funcLine]*ssa.Block{} 146 147 if name == os.Getenv("GOSSAFUNC") { 148 s.f.HTMLWriter = ssa.NewHTMLWriter("ssa.html", s.f.Frontend(), name) 149 // TODO: generate and print a mapping from nodes to values and blocks 150 } 151 152 // Allocate starting block 153 s.f.Entry = s.f.NewBlock(ssa.BlockPlain) 154 155 // Allocate starting values 156 s.labels = map[string]*ssaLabel{} 157 s.labeledNodes = map[*Node]*ssaLabel{} 158 s.fwdVars = map[*Node]*ssa.Value{} 159 s.startmem = s.entryNewValue0(ssa.OpInitMem, types.TypeMem) 160 s.sp = s.entryNewValue0(ssa.OpSP, types.Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead 161 s.sb = s.entryNewValue0(ssa.OpSB, types.Types[TUINTPTR]) 162 163 s.startBlock(s.f.Entry) 164 s.vars[&memVar] = s.startmem 165 166 // Generate addresses of local declarations 167 s.decladdrs = map[*Node]*ssa.Value{} 168 for _, n := range fn.Func.Dcl { 169 switch n.Class() { 170 case PPARAM, PPARAMOUT: 171 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), n, s.sp) 172 if n.Class() == PPARAMOUT && s.canSSA(n) { 173 // Save ssa-able PPARAMOUT variables so we can 174 // store them back to the stack at the end of 175 // the function. 176 s.returns = append(s.returns, n) 177 } 178 case PAUTO: 179 // processed at each use, to prevent Addr coming 180 // before the decl. 181 case PAUTOHEAP: 182 // moved to heap - already handled by frontend 183 case PFUNC: 184 // local function - already handled by frontend 185 default: 186 s.Fatalf("local variable with class %s unimplemented", classnames[n.Class()]) 187 } 188 } 189 190 // Populate SSAable arguments. 191 for _, n := range fn.Func.Dcl { 192 if n.Class() == PPARAM && s.canSSA(n) { 193 s.vars[n] = s.newValue0A(ssa.OpArg, n.Type, n) 194 } 195 } 196 197 // Convert the AST-based IR to the SSA-based IR 198 s.stmtList(fn.Func.Enter) 199 s.stmtList(fn.Nbody) 200 201 // fallthrough to exit 202 if s.curBlock != nil { 203 s.pushLine(fn.Func.Endlineno) 204 s.exit() 205 s.popLine() 206 } 207 208 for _, b := range s.f.Blocks { 209 if b.Pos != src.NoXPos { 210 updateUnsetPredPos(b) 211 } 212 } 213 214 s.insertPhis() 215 216 // Don't carry reference this around longer than necessary 217 s.exitCode = Nodes{} 218 219 // Main call to ssa package to compile function 220 ssa.Compile(s.f) 221 return s.f 222 } 223 224 func updateUnsetPredPos(b *ssa.Block) { 225 for _, e := range b.Preds { 226 p := e.Block() 227 if p.Pos == src.NoXPos && p.Kind == ssa.BlockPlain { 228 pos := b.Pos 229 // TODO: This ought to be produce a better result, but it causes 230 // line 46 ("scanner := bufio.NewScanner(reader)") 231 // to drop out of gdb-dbg and dlv-dbg debug-next traces for hist.go. 232 for _, v := range b.Values { 233 if v.Op == ssa.OpVarDef || v.Op == ssa.OpVarKill || v.Op == ssa.OpVarLive || v.Op == ssa.OpCopy && v.Type == types.TypeMem { 234 continue 235 } 236 if v.Pos != src.NoXPos { 237 pos = v.Pos 238 break 239 } 240 } 241 p.Pos = pos 242 updateUnsetPredPos(p) // We do not expect long chains of these, thus recursion is okay. 243 } 244 } 245 return 246 } 247 248 type state struct { 249 // configuration (arch) information 250 config *ssa.Config 251 252 // function we're building 253 f *ssa.Func 254 255 // Node for function 256 curfn *Node 257 258 // labels and labeled control flow nodes (OFOR, OFORUNTIL, OSWITCH, OSELECT) in f 259 labels map[string]*ssaLabel 260 labeledNodes map[*Node]*ssaLabel 261 262 // Code that must precede any return 263 // (e.g., copying value of heap-escaped paramout back to true paramout) 264 exitCode Nodes 265 266 // unlabeled break and continue statement tracking 267 breakTo *ssa.Block // current target for plain break statement 268 continueTo *ssa.Block // current target for plain continue statement 269 270 // current location where we're interpreting the AST 271 curBlock *ssa.Block 272 273 // variable assignments in the current block (map from variable symbol to ssa value) 274 // *Node is the unique identifier (an ONAME Node) for the variable. 275 // TODO: keep a single varnum map, then make all of these maps slices instead? 276 vars map[*Node]*ssa.Value 277 278 // fwdVars are variables that are used before they are defined in the current block. 279 // This map exists just to coalesce multiple references into a single FwdRef op. 280 // *Node is the unique identifier (an ONAME Node) for the variable. 281 fwdVars map[*Node]*ssa.Value 282 283 // all defined variables at the end of each block. Indexed by block ID. 284 defvars []map[*Node]*ssa.Value 285 286 // addresses of PPARAM and PPARAMOUT variables. 287 decladdrs map[*Node]*ssa.Value 288 289 // starting values. Memory, stack pointer, and globals pointer 290 startmem *ssa.Value 291 sp *ssa.Value 292 sb *ssa.Value 293 294 // line number stack. The current line number is top of stack 295 line []src.XPos 296 // the last line number processed; it may have been popped 297 lastPos src.XPos 298 299 // list of panic calls by function name and line number. 300 // Used to deduplicate panic calls. 301 panics map[funcLine]*ssa.Block 302 303 // list of PPARAMOUT (return) variables. 304 returns []*Node 305 306 cgoUnsafeArgs bool 307 hasdefer bool // whether the function contains a defer statement 308 } 309 310 type funcLine struct { 311 f *obj.LSym 312 base *src.PosBase 313 line uint 314 } 315 316 type ssaLabel struct { 317 target *ssa.Block // block identified by this label 318 breakTarget *ssa.Block // block to break to in control flow node identified by this label 319 continueTarget *ssa.Block // block to continue to in control flow node identified by this label 320 } 321 322 // label returns the label associated with sym, creating it if necessary. 323 func (s *state) label(sym *types.Sym) *ssaLabel { 324 lab := s.labels[sym.Name] 325 if lab == nil { 326 lab = new(ssaLabel) 327 s.labels[sym.Name] = lab 328 } 329 return lab 330 } 331 332 func (s *state) Logf(msg string, args ...interface{}) { s.f.Logf(msg, args...) } 333 func (s *state) Log() bool { return s.f.Log() } 334 func (s *state) Fatalf(msg string, args ...interface{}) { 335 s.f.Frontend().Fatalf(s.peekPos(), msg, args...) 336 } 337 func (s *state) Warnl(pos src.XPos, msg string, args ...interface{}) { s.f.Warnl(pos, msg, args...) } 338 func (s *state) Debug_checknil() bool { return s.f.Frontend().Debug_checknil() } 339 340 var ( 341 // dummy node for the memory variable 342 memVar = Node{Op: ONAME, Sym: &types.Sym{Name: "mem"}} 343 344 // dummy nodes for temporary variables 345 ptrVar = Node{Op: ONAME, Sym: &types.Sym{Name: "ptr"}} 346 lenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "len"}} 347 newlenVar = Node{Op: ONAME, Sym: &types.Sym{Name: "newlen"}} 348 capVar = Node{Op: ONAME, Sym: &types.Sym{Name: "cap"}} 349 typVar = Node{Op: ONAME, Sym: &types.Sym{Name: "typ"}} 350 okVar = Node{Op: ONAME, Sym: &types.Sym{Name: "ok"}} 351 ) 352 353 // startBlock sets the current block we're generating code in to b. 354 func (s *state) startBlock(b *ssa.Block) { 355 if s.curBlock != nil { 356 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock) 357 } 358 s.curBlock = b 359 s.vars = map[*Node]*ssa.Value{} 360 for n := range s.fwdVars { 361 delete(s.fwdVars, n) 362 } 363 } 364 365 // endBlock marks the end of generating code for the current block. 366 // Returns the (former) current block. Returns nil if there is no current 367 // block, i.e. if no code flows to the current execution point. 368 func (s *state) endBlock() *ssa.Block { 369 b := s.curBlock 370 if b == nil { 371 return nil 372 } 373 for len(s.defvars) <= int(b.ID) { 374 s.defvars = append(s.defvars, nil) 375 } 376 s.defvars[b.ID] = s.vars 377 s.curBlock = nil 378 s.vars = nil 379 if len(b.Values) == 0 && b.Kind == ssa.BlockPlain { 380 // Empty plain blocks get the line of their successor (handled after all blocks created), 381 // except for increment blocks in For statements (handled in ssa conversion of OFOR), 382 // and for blocks ending in GOTO/BREAK/CONTINUE. 383 b.Pos = src.NoXPos 384 } else { 385 b.Pos = s.lastPos 386 } 387 return b 388 } 389 390 // pushLine pushes a line number on the line number stack. 391 func (s *state) pushLine(line src.XPos) { 392 if !line.IsKnown() { 393 // the frontend may emit node with line number missing, 394 // use the parent line number in this case. 395 line = s.peekPos() 396 if Debug['K'] != 0 { 397 Warn("buildssa: unknown position (line 0)") 398 } 399 } else { 400 s.lastPos = line 401 } 402 403 s.line = append(s.line, line) 404 } 405 406 // popLine pops the top of the line number stack. 407 func (s *state) popLine() { 408 s.line = s.line[:len(s.line)-1] 409 } 410 411 // peekPos peeks the top of the line number stack. 412 func (s *state) peekPos() src.XPos { 413 return s.line[len(s.line)-1] 414 } 415 416 // newValue0 adds a new value with no arguments to the current block. 417 func (s *state) newValue0(op ssa.Op, t *types.Type) *ssa.Value { 418 return s.curBlock.NewValue0(s.peekPos(), op, t) 419 } 420 421 // newValue0A adds a new value with no arguments and an aux value to the current block. 422 func (s *state) newValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value { 423 return s.curBlock.NewValue0A(s.peekPos(), op, t, aux) 424 } 425 426 // newValue0I adds a new value with no arguments and an auxint value to the current block. 427 func (s *state) newValue0I(op ssa.Op, t *types.Type, auxint int64) *ssa.Value { 428 return s.curBlock.NewValue0I(s.peekPos(), op, t, auxint) 429 } 430 431 // newValue1 adds a new value with one argument to the current block. 432 func (s *state) newValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { 433 return s.curBlock.NewValue1(s.peekPos(), op, t, arg) 434 } 435 436 // newValue1A adds a new value with one argument and an aux value to the current block. 437 func (s *state) newValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value { 438 return s.curBlock.NewValue1A(s.peekPos(), op, t, aux, arg) 439 } 440 441 // newValue1I adds a new value with one argument and an auxint value to the current block. 442 func (s *state) newValue1I(op ssa.Op, t *types.Type, aux int64, arg *ssa.Value) *ssa.Value { 443 return s.curBlock.NewValue1I(s.peekPos(), op, t, aux, arg) 444 } 445 446 // newValue2 adds a new value with two arguments to the current block. 447 func (s *state) newValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value { 448 return s.curBlock.NewValue2(s.peekPos(), op, t, arg0, arg1) 449 } 450 451 // newValue2I adds a new value with two arguments and an auxint value to the current block. 452 func (s *state) newValue2I(op ssa.Op, t *types.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value { 453 return s.curBlock.NewValue2I(s.peekPos(), op, t, aux, arg0, arg1) 454 } 455 456 // newValue3 adds a new value with three arguments to the current block. 457 func (s *state) newValue3(op ssa.Op, t *types.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value { 458 return s.curBlock.NewValue3(s.peekPos(), op, t, arg0, arg1, arg2) 459 } 460 461 // newValue3I adds a new value with three arguments and an auxint value to the current block. 462 func (s *state) newValue3I(op ssa.Op, t *types.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value { 463 return s.curBlock.NewValue3I(s.peekPos(), op, t, aux, arg0, arg1, arg2) 464 } 465 466 // newValue3A adds a new value with three arguments and an aux value to the current block. 467 func (s *state) newValue3A(op ssa.Op, t *types.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value { 468 return s.curBlock.NewValue3A(s.peekPos(), op, t, aux, arg0, arg1, arg2) 469 } 470 471 // newValue4 adds a new value with four arguments to the current block. 472 func (s *state) newValue4(op ssa.Op, t *types.Type, arg0, arg1, arg2, arg3 *ssa.Value) *ssa.Value { 473 return s.curBlock.NewValue4(s.peekPos(), op, t, arg0, arg1, arg2, arg3) 474 } 475 476 // entryNewValue0 adds a new value with no arguments to the entry block. 477 func (s *state) entryNewValue0(op ssa.Op, t *types.Type) *ssa.Value { 478 return s.f.Entry.NewValue0(src.NoXPos, op, t) 479 } 480 481 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block. 482 func (s *state) entryNewValue0A(op ssa.Op, t *types.Type, aux interface{}) *ssa.Value { 483 return s.f.Entry.NewValue0A(s.peekPos(), op, t, aux) 484 } 485 486 // entryNewValue1 adds a new value with one argument to the entry block. 487 func (s *state) entryNewValue1(op ssa.Op, t *types.Type, arg *ssa.Value) *ssa.Value { 488 return s.f.Entry.NewValue1(s.peekPos(), op, t, arg) 489 } 490 491 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block. 492 func (s *state) entryNewValue1I(op ssa.Op, t *types.Type, auxint int64, arg *ssa.Value) *ssa.Value { 493 return s.f.Entry.NewValue1I(s.peekPos(), op, t, auxint, arg) 494 } 495 496 // entryNewValue1A adds a new value with one argument and an aux value to the entry block. 497 func (s *state) entryNewValue1A(op ssa.Op, t *types.Type, aux interface{}, arg *ssa.Value) *ssa.Value { 498 return s.f.Entry.NewValue1A(s.peekPos(), op, t, aux, arg) 499 } 500 501 // entryNewValue2 adds a new value with two arguments to the entry block. 502 func (s *state) entryNewValue2(op ssa.Op, t *types.Type, arg0, arg1 *ssa.Value) *ssa.Value { 503 return s.f.Entry.NewValue2(s.peekPos(), op, t, arg0, arg1) 504 } 505 506 // const* routines add a new const value to the entry block. 507 func (s *state) constSlice(t *types.Type) *ssa.Value { 508 return s.f.ConstSlice(s.peekPos(), t) 509 } 510 func (s *state) constInterface(t *types.Type) *ssa.Value { 511 return s.f.ConstInterface(s.peekPos(), t) 512 } 513 func (s *state) constNil(t *types.Type) *ssa.Value { return s.f.ConstNil(s.peekPos(), t) } 514 func (s *state) constEmptyString(t *types.Type) *ssa.Value { 515 return s.f.ConstEmptyString(s.peekPos(), t) 516 } 517 func (s *state) constBool(c bool) *ssa.Value { 518 return s.f.ConstBool(s.peekPos(), types.Types[TBOOL], c) 519 } 520 func (s *state) constInt8(t *types.Type, c int8) *ssa.Value { 521 return s.f.ConstInt8(s.peekPos(), t, c) 522 } 523 func (s *state) constInt16(t *types.Type, c int16) *ssa.Value { 524 return s.f.ConstInt16(s.peekPos(), t, c) 525 } 526 func (s *state) constInt32(t *types.Type, c int32) *ssa.Value { 527 return s.f.ConstInt32(s.peekPos(), t, c) 528 } 529 func (s *state) constInt64(t *types.Type, c int64) *ssa.Value { 530 return s.f.ConstInt64(s.peekPos(), t, c) 531 } 532 func (s *state) constFloat32(t *types.Type, c float64) *ssa.Value { 533 return s.f.ConstFloat32(s.peekPos(), t, c) 534 } 535 func (s *state) constFloat64(t *types.Type, c float64) *ssa.Value { 536 return s.f.ConstFloat64(s.peekPos(), t, c) 537 } 538 func (s *state) constInt(t *types.Type, c int64) *ssa.Value { 539 if s.config.PtrSize == 8 { 540 return s.constInt64(t, c) 541 } 542 if int64(int32(c)) != c { 543 s.Fatalf("integer constant too big %d", c) 544 } 545 return s.constInt32(t, int32(c)) 546 } 547 func (s *state) constOffPtrSP(t *types.Type, c int64) *ssa.Value { 548 return s.f.ConstOffPtrSP(s.peekPos(), t, c, s.sp) 549 } 550 551 // stmtList converts the statement list n to SSA and adds it to s. 552 func (s *state) stmtList(l Nodes) { 553 for _, n := range l.Slice() { 554 s.stmt(n) 555 } 556 } 557 558 // stmt converts the statement n to SSA and adds it to s. 559 func (s *state) stmt(n *Node) { 560 if !(n.Op == OVARKILL || n.Op == OVARLIVE) { 561 // OVARKILL and OVARLIVE are invisible to the programmer, so we don't use their line numbers to avoid confusion in debugging. 562 s.pushLine(n.Pos) 563 defer s.popLine() 564 } 565 566 // If s.curBlock is nil, and n isn't a label (which might have an associated goto somewhere), 567 // then this code is dead. Stop here. 568 if s.curBlock == nil && n.Op != OLABEL { 569 return 570 } 571 572 s.stmtList(n.Ninit) 573 switch n.Op { 574 575 case OBLOCK: 576 s.stmtList(n.List) 577 578 // No-ops 579 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL: 580 581 // Expression statements 582 case OCALLFUNC: 583 if isIntrinsicCall(n) { 584 s.intrinsicCall(n) 585 return 586 } 587 fallthrough 588 589 case OCALLMETH, OCALLINTER: 590 s.call(n, callNormal) 591 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class() == PFUNC { 592 if fn := n.Left.Sym.Name; compiling_runtime && fn == "throw" || 593 n.Left.Sym.Pkg == Runtimepkg && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block") { 594 m := s.mem() 595 b := s.endBlock() 596 b.Kind = ssa.BlockExit 597 b.SetControl(m) 598 // TODO: never rewrite OPANIC to OCALLFUNC in the 599 // first place. Need to wait until all backends 600 // go through SSA. 601 } 602 } 603 case ODEFER: 604 s.call(n.Left, callDefer) 605 case OPROC: 606 s.call(n.Left, callGo) 607 608 case OAS2DOTTYPE: 609 res, resok := s.dottype(n.Rlist.First(), true) 610 deref := false 611 if !canSSAType(n.Rlist.First().Type) { 612 if res.Op != ssa.OpLoad { 613 s.Fatalf("dottype of non-load") 614 } 615 mem := s.mem() 616 if mem.Op == ssa.OpVarKill { 617 mem = mem.Args[0] 618 } 619 if res.Args[1] != mem { 620 s.Fatalf("memory no longer live from 2-result dottype load") 621 } 622 deref = true 623 res = res.Args[0] 624 } 625 s.assign(n.List.First(), res, deref, 0) 626 s.assign(n.List.Second(), resok, false, 0) 627 return 628 629 case OAS2FUNC: 630 // We come here only when it is an intrinsic call returning two values. 631 if !isIntrinsicCall(n.Rlist.First()) { 632 s.Fatalf("non-intrinsic AS2FUNC not expanded %v", n.Rlist.First()) 633 } 634 v := s.intrinsicCall(n.Rlist.First()) 635 v1 := s.newValue1(ssa.OpSelect0, n.List.First().Type, v) 636 v2 := s.newValue1(ssa.OpSelect1, n.List.Second().Type, v) 637 s.assign(n.List.First(), v1, false, 0) 638 s.assign(n.List.Second(), v2, false, 0) 639 return 640 641 case ODCL: 642 if n.Left.Class() == PAUTOHEAP { 643 Fatalf("DCL %v", n) 644 } 645 646 case OLABEL: 647 sym := n.Left.Sym 648 lab := s.label(sym) 649 650 // Associate label with its control flow node, if any 651 if ctl := n.labeledControl(); ctl != nil { 652 s.labeledNodes[ctl] = lab 653 } 654 655 // The label might already have a target block via a goto. 656 if lab.target == nil { 657 lab.target = s.f.NewBlock(ssa.BlockPlain) 658 } 659 660 // Go to that label. 661 // (We pretend "label:" is preceded by "goto label", unless the predecessor is unreachable.) 662 if s.curBlock != nil { 663 b := s.endBlock() 664 b.AddEdgeTo(lab.target) 665 } 666 s.startBlock(lab.target) 667 668 case OGOTO: 669 sym := n.Left.Sym 670 671 lab := s.label(sym) 672 if lab.target == nil { 673 lab.target = s.f.NewBlock(ssa.BlockPlain) 674 } 675 676 b := s.endBlock() 677 b.Pos = s.lastPos // Do this even if b is an empty block. 678 b.AddEdgeTo(lab.target) 679 680 case OAS: 681 if n.Left == n.Right && n.Left.Op == ONAME { 682 // An x=x assignment. No point in doing anything 683 // here. In addition, skipping this assignment 684 // prevents generating: 685 // VARDEF x 686 // COPY x -> x 687 // which is bad because x is incorrectly considered 688 // dead before the vardef. See issue #14904. 689 return 690 } 691 692 // Evaluate RHS. 693 rhs := n.Right 694 if rhs != nil { 695 switch rhs.Op { 696 case OSTRUCTLIT, OARRAYLIT, OSLICELIT: 697 // All literals with nonzero fields have already been 698 // rewritten during walk. Any that remain are just T{} 699 // or equivalents. Use the zero value. 700 if !iszero(rhs) { 701 Fatalf("literal with nonzero value in SSA: %v", rhs) 702 } 703 rhs = nil 704 case OAPPEND: 705 // Check whether we're writing the result of an append back to the same slice. 706 // If so, we handle it specially to avoid write barriers on the fast 707 // (non-growth) path. 708 if !samesafeexpr(n.Left, rhs.List.First()) { 709 break 710 } 711 // If the slice can be SSA'd, it'll be on the stack, 712 // so there will be no write barriers, 713 // so there's no need to attempt to prevent them. 714 if s.canSSA(n.Left) { 715 if Debug_append > 0 { // replicating old diagnostic message 716 Warnl(n.Pos, "append: len-only update (in local slice)") 717 } 718 break 719 } 720 if Debug_append > 0 { 721 Warnl(n.Pos, "append: len-only update") 722 } 723 s.append(rhs, true) 724 return 725 } 726 } 727 728 if isblank(n.Left) { 729 // _ = rhs 730 // Just evaluate rhs for side-effects. 731 if rhs != nil { 732 s.expr(rhs) 733 } 734 return 735 } 736 737 var t *types.Type 738 if n.Right != nil { 739 t = n.Right.Type 740 } else { 741 t = n.Left.Type 742 } 743 744 var r *ssa.Value 745 deref := !canSSAType(t) 746 if deref { 747 if rhs == nil { 748 r = nil // Signal assign to use OpZero. 749 } else { 750 r = s.addr(rhs, false) 751 } 752 } else { 753 if rhs == nil { 754 r = s.zeroVal(t) 755 } else { 756 r = s.expr(rhs) 757 } 758 } 759 760 var skip skipMask 761 if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) { 762 // We're assigning a slicing operation back to its source. 763 // Don't write back fields we aren't changing. See issue #14855. 764 i, j, k := rhs.SliceBounds() 765 if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) { 766 // [0:...] is the same as [:...] 767 i = nil 768 } 769 // TODO: detect defaults for len/cap also. 770 // Currently doesn't really work because (*p)[:len(*p)] appears here as: 771 // tmp = len(*p) 772 // (*p)[:tmp] 773 //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) { 774 // j = nil 775 //} 776 //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) { 777 // k = nil 778 //} 779 if i == nil { 780 skip |= skipPtr 781 if j == nil { 782 skip |= skipLen 783 } 784 if k == nil { 785 skip |= skipCap 786 } 787 } 788 } 789 790 s.assign(n.Left, r, deref, skip) 791 792 case OIF: 793 bThen := s.f.NewBlock(ssa.BlockPlain) 794 bEnd := s.f.NewBlock(ssa.BlockPlain) 795 var bElse *ssa.Block 796 var likely int8 797 if n.Likely() { 798 likely = 1 799 } 800 if n.Rlist.Len() != 0 { 801 bElse = s.f.NewBlock(ssa.BlockPlain) 802 s.condBranch(n.Left, bThen, bElse, likely) 803 } else { 804 s.condBranch(n.Left, bThen, bEnd, likely) 805 } 806 807 s.startBlock(bThen) 808 s.stmtList(n.Nbody) 809 if b := s.endBlock(); b != nil { 810 b.AddEdgeTo(bEnd) 811 } 812 813 if n.Rlist.Len() != 0 { 814 s.startBlock(bElse) 815 s.stmtList(n.Rlist) 816 if b := s.endBlock(); b != nil { 817 b.AddEdgeTo(bEnd) 818 } 819 } 820 s.startBlock(bEnd) 821 822 case ORETURN: 823 s.stmtList(n.List) 824 s.exit() 825 case ORETJMP: 826 s.stmtList(n.List) 827 b := s.exit() 828 b.Kind = ssa.BlockRetJmp // override BlockRet 829 b.Aux = n.Sym.Linksym() 830 831 case OCONTINUE, OBREAK: 832 var to *ssa.Block 833 if n.Left == nil { 834 // plain break/continue 835 switch n.Op { 836 case OCONTINUE: 837 to = s.continueTo 838 case OBREAK: 839 to = s.breakTo 840 } 841 } else { 842 // labeled break/continue; look up the target 843 sym := n.Left.Sym 844 lab := s.label(sym) 845 switch n.Op { 846 case OCONTINUE: 847 to = lab.continueTarget 848 case OBREAK: 849 to = lab.breakTarget 850 } 851 } 852 853 b := s.endBlock() 854 b.Pos = s.lastPos // Do this even if b is an empty block. 855 b.AddEdgeTo(to) 856 857 case OFOR, OFORUNTIL: 858 // OFOR: for Ninit; Left; Right { Nbody } 859 // For = cond; body; incr 860 // Foruntil = body; incr; cond 861 bCond := s.f.NewBlock(ssa.BlockPlain) 862 bBody := s.f.NewBlock(ssa.BlockPlain) 863 bIncr := s.f.NewBlock(ssa.BlockPlain) 864 bEnd := s.f.NewBlock(ssa.BlockPlain) 865 866 // first, jump to condition test (OFOR) or body (OFORUNTIL) 867 b := s.endBlock() 868 if n.Op == OFOR { 869 b.AddEdgeTo(bCond) 870 // generate code to test condition 871 s.startBlock(bCond) 872 if n.Left != nil { 873 s.condBranch(n.Left, bBody, bEnd, 1) 874 } else { 875 b := s.endBlock() 876 b.Kind = ssa.BlockPlain 877 b.AddEdgeTo(bBody) 878 } 879 880 } else { 881 b.AddEdgeTo(bBody) 882 } 883 884 // set up for continue/break in body 885 prevContinue := s.continueTo 886 prevBreak := s.breakTo 887 s.continueTo = bIncr 888 s.breakTo = bEnd 889 lab := s.labeledNodes[n] 890 if lab != nil { 891 // labeled for loop 892 lab.continueTarget = bIncr 893 lab.breakTarget = bEnd 894 } 895 896 // generate body 897 s.startBlock(bBody) 898 s.stmtList(n.Nbody) 899 900 // tear down continue/break 901 s.continueTo = prevContinue 902 s.breakTo = prevBreak 903 if lab != nil { 904 lab.continueTarget = nil 905 lab.breakTarget = nil 906 } 907 908 // done with body, goto incr 909 if b := s.endBlock(); b != nil { 910 b.AddEdgeTo(bIncr) 911 } 912 913 // generate incr 914 s.startBlock(bIncr) 915 if n.Right != nil { 916 s.stmt(n.Right) 917 } 918 if b := s.endBlock(); b != nil { 919 b.AddEdgeTo(bCond) 920 // It can happen that bIncr ends in a block containing only VARKILL, 921 // and that muddles the debugging experience. 922 if n.Op != OFORUNTIL && b.Pos == src.NoXPos { 923 b.Pos = bCond.Pos 924 } 925 } 926 927 if n.Op == OFORUNTIL { 928 // generate code to test condition 929 s.startBlock(bCond) 930 if n.Left != nil { 931 s.condBranch(n.Left, bBody, bEnd, 1) 932 } else { 933 b := s.endBlock() 934 b.Kind = ssa.BlockPlain 935 b.AddEdgeTo(bBody) 936 } 937 } 938 939 s.startBlock(bEnd) 940 941 case OSWITCH, OSELECT: 942 // These have been mostly rewritten by the front end into their Nbody fields. 943 // Our main task is to correctly hook up any break statements. 944 bEnd := s.f.NewBlock(ssa.BlockPlain) 945 946 prevBreak := s.breakTo 947 s.breakTo = bEnd 948 lab := s.labeledNodes[n] 949 if lab != nil { 950 // labeled 951 lab.breakTarget = bEnd 952 } 953 954 // generate body code 955 s.stmtList(n.Nbody) 956 957 s.breakTo = prevBreak 958 if lab != nil { 959 lab.breakTarget = nil 960 } 961 962 // walk adds explicit OBREAK nodes to the end of all reachable code paths. 963 // If we still have a current block here, then mark it unreachable. 964 if s.curBlock != nil { 965 m := s.mem() 966 b := s.endBlock() 967 b.Kind = ssa.BlockExit 968 b.SetControl(m) 969 } 970 s.startBlock(bEnd) 971 972 case OVARKILL: 973 // Insert a varkill op to record that a variable is no longer live. 974 // We only care about liveness info at call sites, so putting the 975 // varkill in the store chain is enough to keep it correctly ordered 976 // with respect to call ops. 977 if !s.canSSA(n.Left) { 978 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, n.Left, s.mem()) 979 } 980 981 case OVARLIVE: 982 // Insert a varlive op to record that a variable is still live. 983 if !n.Left.Addrtaken() { 984 s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left) 985 } 986 switch n.Left.Class() { 987 case PAUTO, PPARAM, PPARAMOUT: 988 default: 989 s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left) 990 } 991 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem()) 992 993 case OCHECKNIL: 994 p := s.expr(n.Left) 995 s.nilCheck(p) 996 997 default: 998 s.Fatalf("unhandled stmt %v", n.Op) 999 } 1000 } 1001 1002 // exit processes any code that needs to be generated just before returning. 1003 // It returns a BlockRet block that ends the control flow. Its control value 1004 // will be set to the final memory state. 1005 func (s *state) exit() *ssa.Block { 1006 if s.hasdefer { 1007 s.rtcall(Deferreturn, true, nil) 1008 } 1009 1010 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT 1011 // variables back to the stack. 1012 s.stmtList(s.exitCode) 1013 1014 // Store SSAable PPARAMOUT variables back to stack locations. 1015 for _, n := range s.returns { 1016 addr := s.decladdrs[n] 1017 val := s.variable(n, n.Type) 1018 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, n, s.mem()) 1019 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, n.Type, addr, val, s.mem()) 1020 // TODO: if val is ever spilled, we'd like to use the 1021 // PPARAMOUT slot for spilling it. That won't happen 1022 // currently. 1023 } 1024 1025 // Do actual return. 1026 m := s.mem() 1027 b := s.endBlock() 1028 b.Kind = ssa.BlockRet 1029 b.SetControl(m) 1030 return b 1031 } 1032 1033 type opAndType struct { 1034 op Op 1035 etype types.EType 1036 } 1037 1038 var opToSSA = map[opAndType]ssa.Op{ 1039 opAndType{OADD, TINT8}: ssa.OpAdd8, 1040 opAndType{OADD, TUINT8}: ssa.OpAdd8, 1041 opAndType{OADD, TINT16}: ssa.OpAdd16, 1042 opAndType{OADD, TUINT16}: ssa.OpAdd16, 1043 opAndType{OADD, TINT32}: ssa.OpAdd32, 1044 opAndType{OADD, TUINT32}: ssa.OpAdd32, 1045 opAndType{OADD, TPTR32}: ssa.OpAdd32, 1046 opAndType{OADD, TINT64}: ssa.OpAdd64, 1047 opAndType{OADD, TUINT64}: ssa.OpAdd64, 1048 opAndType{OADD, TPTR64}: ssa.OpAdd64, 1049 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F, 1050 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F, 1051 1052 opAndType{OSUB, TINT8}: ssa.OpSub8, 1053 opAndType{OSUB, TUINT8}: ssa.OpSub8, 1054 opAndType{OSUB, TINT16}: ssa.OpSub16, 1055 opAndType{OSUB, TUINT16}: ssa.OpSub16, 1056 opAndType{OSUB, TINT32}: ssa.OpSub32, 1057 opAndType{OSUB, TUINT32}: ssa.OpSub32, 1058 opAndType{OSUB, TINT64}: ssa.OpSub64, 1059 opAndType{OSUB, TUINT64}: ssa.OpSub64, 1060 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F, 1061 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F, 1062 1063 opAndType{ONOT, TBOOL}: ssa.OpNot, 1064 1065 opAndType{OMINUS, TINT8}: ssa.OpNeg8, 1066 opAndType{OMINUS, TUINT8}: ssa.OpNeg8, 1067 opAndType{OMINUS, TINT16}: ssa.OpNeg16, 1068 opAndType{OMINUS, TUINT16}: ssa.OpNeg16, 1069 opAndType{OMINUS, TINT32}: ssa.OpNeg32, 1070 opAndType{OMINUS, TUINT32}: ssa.OpNeg32, 1071 opAndType{OMINUS, TINT64}: ssa.OpNeg64, 1072 opAndType{OMINUS, TUINT64}: ssa.OpNeg64, 1073 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F, 1074 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F, 1075 1076 opAndType{OCOM, TINT8}: ssa.OpCom8, 1077 opAndType{OCOM, TUINT8}: ssa.OpCom8, 1078 opAndType{OCOM, TINT16}: ssa.OpCom16, 1079 opAndType{OCOM, TUINT16}: ssa.OpCom16, 1080 opAndType{OCOM, TINT32}: ssa.OpCom32, 1081 opAndType{OCOM, TUINT32}: ssa.OpCom32, 1082 opAndType{OCOM, TINT64}: ssa.OpCom64, 1083 opAndType{OCOM, TUINT64}: ssa.OpCom64, 1084 1085 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag, 1086 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag, 1087 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal, 1088 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal, 1089 1090 opAndType{OMUL, TINT8}: ssa.OpMul8, 1091 opAndType{OMUL, TUINT8}: ssa.OpMul8, 1092 opAndType{OMUL, TINT16}: ssa.OpMul16, 1093 opAndType{OMUL, TUINT16}: ssa.OpMul16, 1094 opAndType{OMUL, TINT32}: ssa.OpMul32, 1095 opAndType{OMUL, TUINT32}: ssa.OpMul32, 1096 opAndType{OMUL, TINT64}: ssa.OpMul64, 1097 opAndType{OMUL, TUINT64}: ssa.OpMul64, 1098 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F, 1099 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F, 1100 1101 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F, 1102 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F, 1103 1104 opAndType{ODIV, TINT8}: ssa.OpDiv8, 1105 opAndType{ODIV, TUINT8}: ssa.OpDiv8u, 1106 opAndType{ODIV, TINT16}: ssa.OpDiv16, 1107 opAndType{ODIV, TUINT16}: ssa.OpDiv16u, 1108 opAndType{ODIV, TINT32}: ssa.OpDiv32, 1109 opAndType{ODIV, TUINT32}: ssa.OpDiv32u, 1110 opAndType{ODIV, TINT64}: ssa.OpDiv64, 1111 opAndType{ODIV, TUINT64}: ssa.OpDiv64u, 1112 1113 opAndType{OMOD, TINT8}: ssa.OpMod8, 1114 opAndType{OMOD, TUINT8}: ssa.OpMod8u, 1115 opAndType{OMOD, TINT16}: ssa.OpMod16, 1116 opAndType{OMOD, TUINT16}: ssa.OpMod16u, 1117 opAndType{OMOD, TINT32}: ssa.OpMod32, 1118 opAndType{OMOD, TUINT32}: ssa.OpMod32u, 1119 opAndType{OMOD, TINT64}: ssa.OpMod64, 1120 opAndType{OMOD, TUINT64}: ssa.OpMod64u, 1121 1122 opAndType{OAND, TINT8}: ssa.OpAnd8, 1123 opAndType{OAND, TUINT8}: ssa.OpAnd8, 1124 opAndType{OAND, TINT16}: ssa.OpAnd16, 1125 opAndType{OAND, TUINT16}: ssa.OpAnd16, 1126 opAndType{OAND, TINT32}: ssa.OpAnd32, 1127 opAndType{OAND, TUINT32}: ssa.OpAnd32, 1128 opAndType{OAND, TINT64}: ssa.OpAnd64, 1129 opAndType{OAND, TUINT64}: ssa.OpAnd64, 1130 1131 opAndType{OOR, TINT8}: ssa.OpOr8, 1132 opAndType{OOR, TUINT8}: ssa.OpOr8, 1133 opAndType{OOR, TINT16}: ssa.OpOr16, 1134 opAndType{OOR, TUINT16}: ssa.OpOr16, 1135 opAndType{OOR, TINT32}: ssa.OpOr32, 1136 opAndType{OOR, TUINT32}: ssa.OpOr32, 1137 opAndType{OOR, TINT64}: ssa.OpOr64, 1138 opAndType{OOR, TUINT64}: ssa.OpOr64, 1139 1140 opAndType{OXOR, TINT8}: ssa.OpXor8, 1141 opAndType{OXOR, TUINT8}: ssa.OpXor8, 1142 opAndType{OXOR, TINT16}: ssa.OpXor16, 1143 opAndType{OXOR, TUINT16}: ssa.OpXor16, 1144 opAndType{OXOR, TINT32}: ssa.OpXor32, 1145 opAndType{OXOR, TUINT32}: ssa.OpXor32, 1146 opAndType{OXOR, TINT64}: ssa.OpXor64, 1147 opAndType{OXOR, TUINT64}: ssa.OpXor64, 1148 1149 opAndType{OEQ, TBOOL}: ssa.OpEqB, 1150 opAndType{OEQ, TINT8}: ssa.OpEq8, 1151 opAndType{OEQ, TUINT8}: ssa.OpEq8, 1152 opAndType{OEQ, TINT16}: ssa.OpEq16, 1153 opAndType{OEQ, TUINT16}: ssa.OpEq16, 1154 opAndType{OEQ, TINT32}: ssa.OpEq32, 1155 opAndType{OEQ, TUINT32}: ssa.OpEq32, 1156 opAndType{OEQ, TINT64}: ssa.OpEq64, 1157 opAndType{OEQ, TUINT64}: ssa.OpEq64, 1158 opAndType{OEQ, TINTER}: ssa.OpEqInter, 1159 opAndType{OEQ, TSLICE}: ssa.OpEqSlice, 1160 opAndType{OEQ, TFUNC}: ssa.OpEqPtr, 1161 opAndType{OEQ, TMAP}: ssa.OpEqPtr, 1162 opAndType{OEQ, TCHAN}: ssa.OpEqPtr, 1163 opAndType{OEQ, TPTR32}: ssa.OpEqPtr, 1164 opAndType{OEQ, TPTR64}: ssa.OpEqPtr, 1165 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr, 1166 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr, 1167 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F, 1168 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F, 1169 1170 opAndType{ONE, TBOOL}: ssa.OpNeqB, 1171 opAndType{ONE, TINT8}: ssa.OpNeq8, 1172 opAndType{ONE, TUINT8}: ssa.OpNeq8, 1173 opAndType{ONE, TINT16}: ssa.OpNeq16, 1174 opAndType{ONE, TUINT16}: ssa.OpNeq16, 1175 opAndType{ONE, TINT32}: ssa.OpNeq32, 1176 opAndType{ONE, TUINT32}: ssa.OpNeq32, 1177 opAndType{ONE, TINT64}: ssa.OpNeq64, 1178 opAndType{ONE, TUINT64}: ssa.OpNeq64, 1179 opAndType{ONE, TINTER}: ssa.OpNeqInter, 1180 opAndType{ONE, TSLICE}: ssa.OpNeqSlice, 1181 opAndType{ONE, TFUNC}: ssa.OpNeqPtr, 1182 opAndType{ONE, TMAP}: ssa.OpNeqPtr, 1183 opAndType{ONE, TCHAN}: ssa.OpNeqPtr, 1184 opAndType{ONE, TPTR32}: ssa.OpNeqPtr, 1185 opAndType{ONE, TPTR64}: ssa.OpNeqPtr, 1186 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr, 1187 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr, 1188 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F, 1189 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F, 1190 1191 opAndType{OLT, TINT8}: ssa.OpLess8, 1192 opAndType{OLT, TUINT8}: ssa.OpLess8U, 1193 opAndType{OLT, TINT16}: ssa.OpLess16, 1194 opAndType{OLT, TUINT16}: ssa.OpLess16U, 1195 opAndType{OLT, TINT32}: ssa.OpLess32, 1196 opAndType{OLT, TUINT32}: ssa.OpLess32U, 1197 opAndType{OLT, TINT64}: ssa.OpLess64, 1198 opAndType{OLT, TUINT64}: ssa.OpLess64U, 1199 opAndType{OLT, TFLOAT64}: ssa.OpLess64F, 1200 opAndType{OLT, TFLOAT32}: ssa.OpLess32F, 1201 1202 opAndType{OGT, TINT8}: ssa.OpGreater8, 1203 opAndType{OGT, TUINT8}: ssa.OpGreater8U, 1204 opAndType{OGT, TINT16}: ssa.OpGreater16, 1205 opAndType{OGT, TUINT16}: ssa.OpGreater16U, 1206 opAndType{OGT, TINT32}: ssa.OpGreater32, 1207 opAndType{OGT, TUINT32}: ssa.OpGreater32U, 1208 opAndType{OGT, TINT64}: ssa.OpGreater64, 1209 opAndType{OGT, TUINT64}: ssa.OpGreater64U, 1210 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F, 1211 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F, 1212 1213 opAndType{OLE, TINT8}: ssa.OpLeq8, 1214 opAndType{OLE, TUINT8}: ssa.OpLeq8U, 1215 opAndType{OLE, TINT16}: ssa.OpLeq16, 1216 opAndType{OLE, TUINT16}: ssa.OpLeq16U, 1217 opAndType{OLE, TINT32}: ssa.OpLeq32, 1218 opAndType{OLE, TUINT32}: ssa.OpLeq32U, 1219 opAndType{OLE, TINT64}: ssa.OpLeq64, 1220 opAndType{OLE, TUINT64}: ssa.OpLeq64U, 1221 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F, 1222 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F, 1223 1224 opAndType{OGE, TINT8}: ssa.OpGeq8, 1225 opAndType{OGE, TUINT8}: ssa.OpGeq8U, 1226 opAndType{OGE, TINT16}: ssa.OpGeq16, 1227 opAndType{OGE, TUINT16}: ssa.OpGeq16U, 1228 opAndType{OGE, TINT32}: ssa.OpGeq32, 1229 opAndType{OGE, TUINT32}: ssa.OpGeq32U, 1230 opAndType{OGE, TINT64}: ssa.OpGeq64, 1231 opAndType{OGE, TUINT64}: ssa.OpGeq64U, 1232 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F, 1233 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F, 1234 } 1235 1236 func (s *state) concreteEtype(t *types.Type) types.EType { 1237 e := t.Etype 1238 switch e { 1239 default: 1240 return e 1241 case TINT: 1242 if s.config.PtrSize == 8 { 1243 return TINT64 1244 } 1245 return TINT32 1246 case TUINT: 1247 if s.config.PtrSize == 8 { 1248 return TUINT64 1249 } 1250 return TUINT32 1251 case TUINTPTR: 1252 if s.config.PtrSize == 8 { 1253 return TUINT64 1254 } 1255 return TUINT32 1256 } 1257 } 1258 1259 func (s *state) ssaOp(op Op, t *types.Type) ssa.Op { 1260 etype := s.concreteEtype(t) 1261 x, ok := opToSSA[opAndType{op, etype}] 1262 if !ok { 1263 s.Fatalf("unhandled binary op %v %s", op, etype) 1264 } 1265 return x 1266 } 1267 1268 func floatForComplex(t *types.Type) *types.Type { 1269 if t.Size() == 8 { 1270 return types.Types[TFLOAT32] 1271 } else { 1272 return types.Types[TFLOAT64] 1273 } 1274 } 1275 1276 type opAndTwoTypes struct { 1277 op Op 1278 etype1 types.EType 1279 etype2 types.EType 1280 } 1281 1282 type twoTypes struct { 1283 etype1 types.EType 1284 etype2 types.EType 1285 } 1286 1287 type twoOpsAndType struct { 1288 op1 ssa.Op 1289 op2 ssa.Op 1290 intermediateType types.EType 1291 } 1292 1293 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{ 1294 1295 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32}, 1296 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32}, 1297 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32}, 1298 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64}, 1299 1300 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32}, 1301 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32}, 1302 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32}, 1303 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64}, 1304 1305 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32}, 1306 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32}, 1307 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32}, 1308 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64}, 1309 1310 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32}, 1311 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32}, 1312 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32}, 1313 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64}, 1314 // unsigned 1315 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32}, 1316 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32}, 1317 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned 1318 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead 1319 1320 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32}, 1321 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32}, 1322 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned 1323 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead 1324 1325 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32}, 1326 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32}, 1327 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned 1328 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead 1329 1330 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32}, 1331 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32}, 1332 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned 1333 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead 1334 1335 // float 1336 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32}, 1337 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpRound64F, ssa.OpCopy, TFLOAT64}, 1338 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpRound32F, ssa.OpCopy, TFLOAT32}, 1339 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64}, 1340 } 1341 1342 // this map is used only for 32-bit arch, and only includes the difference 1343 // on 32-bit arch, don't use int64<->float conversion for uint32 1344 var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{ 1345 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto32F, TUINT32}, 1346 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto64F, TUINT32}, 1347 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto32U, ssa.OpCopy, TUINT32}, 1348 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto32U, ssa.OpCopy, TUINT32}, 1349 } 1350 1351 // uint64<->float conversions, only on machines that have intructions for that 1352 var uint64fpConvOpToSSA = map[twoTypes]twoOpsAndType{ 1353 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto32F, TUINT64}, 1354 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64Uto64F, TUINT64}, 1355 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpCvt32Fto64U, ssa.OpCopy, TUINT64}, 1356 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpCvt64Fto64U, ssa.OpCopy, TUINT64}, 1357 } 1358 1359 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{ 1360 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8, 1361 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8, 1362 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16, 1363 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16, 1364 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32, 1365 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32, 1366 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64, 1367 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64, 1368 1369 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8, 1370 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8, 1371 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16, 1372 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16, 1373 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32, 1374 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32, 1375 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64, 1376 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64, 1377 1378 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8, 1379 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8, 1380 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16, 1381 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16, 1382 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32, 1383 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32, 1384 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64, 1385 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64, 1386 1387 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8, 1388 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8, 1389 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16, 1390 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16, 1391 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32, 1392 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32, 1393 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64, 1394 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64, 1395 1396 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8, 1397 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8, 1398 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16, 1399 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16, 1400 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32, 1401 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32, 1402 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64, 1403 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64, 1404 1405 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8, 1406 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8, 1407 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16, 1408 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16, 1409 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32, 1410 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32, 1411 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64, 1412 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64, 1413 1414 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8, 1415 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8, 1416 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16, 1417 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16, 1418 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32, 1419 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32, 1420 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64, 1421 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64, 1422 1423 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8, 1424 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8, 1425 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16, 1426 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16, 1427 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32, 1428 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32, 1429 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64, 1430 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64, 1431 } 1432 1433 func (s *state) ssaShiftOp(op Op, t *types.Type, u *types.Type) ssa.Op { 1434 etype1 := s.concreteEtype(t) 1435 etype2 := s.concreteEtype(u) 1436 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}] 1437 if !ok { 1438 s.Fatalf("unhandled shift op %v etype=%s/%s", op, etype1, etype2) 1439 } 1440 return x 1441 } 1442 1443 // expr converts the expression n to ssa, adds it to s and returns the ssa result. 1444 func (s *state) expr(n *Node) *ssa.Value { 1445 if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) { 1446 // ONAMEs and named OLITERALs have the line number 1447 // of the decl, not the use. See issue 14742. 1448 s.pushLine(n.Pos) 1449 defer s.popLine() 1450 } 1451 1452 s.stmtList(n.Ninit) 1453 switch n.Op { 1454 case OARRAYBYTESTRTMP: 1455 slice := s.expr(n.Left) 1456 ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice) 1457 len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice) 1458 return s.newValue2(ssa.OpStringMake, n.Type, ptr, len) 1459 case OSTRARRAYBYTETMP: 1460 str := s.expr(n.Left) 1461 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, str) 1462 len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str) 1463 return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len) 1464 case OCFUNC: 1465 aux := n.Left.Sym.Linksym() 1466 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb) 1467 case ONAME: 1468 if n.Class() == PFUNC { 1469 // "value" of a function is the address of the function's closure 1470 sym := funcsym(n.Sym).Linksym() 1471 return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb) 1472 } 1473 if s.canSSA(n) { 1474 return s.variable(n, n.Type) 1475 } 1476 addr := s.addr(n, false) 1477 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) 1478 case OCLOSUREVAR: 1479 addr := s.addr(n, false) 1480 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) 1481 case OLITERAL: 1482 switch u := n.Val().U.(type) { 1483 case *Mpint: 1484 i := u.Int64() 1485 switch n.Type.Size() { 1486 case 1: 1487 return s.constInt8(n.Type, int8(i)) 1488 case 2: 1489 return s.constInt16(n.Type, int16(i)) 1490 case 4: 1491 return s.constInt32(n.Type, int32(i)) 1492 case 8: 1493 return s.constInt64(n.Type, i) 1494 default: 1495 s.Fatalf("bad integer size %d", n.Type.Size()) 1496 return nil 1497 } 1498 case string: 1499 if u == "" { 1500 return s.constEmptyString(n.Type) 1501 } 1502 return s.entryNewValue0A(ssa.OpConstString, n.Type, u) 1503 case bool: 1504 return s.constBool(u) 1505 case *NilVal: 1506 t := n.Type 1507 switch { 1508 case t.IsSlice(): 1509 return s.constSlice(t) 1510 case t.IsInterface(): 1511 return s.constInterface(t) 1512 default: 1513 return s.constNil(t) 1514 } 1515 case *Mpflt: 1516 switch n.Type.Size() { 1517 case 4: 1518 return s.constFloat32(n.Type, u.Float32()) 1519 case 8: 1520 return s.constFloat64(n.Type, u.Float64()) 1521 default: 1522 s.Fatalf("bad float size %d", n.Type.Size()) 1523 return nil 1524 } 1525 case *Mpcplx: 1526 r := &u.Real 1527 i := &u.Imag 1528 switch n.Type.Size() { 1529 case 8: 1530 pt := types.Types[TFLOAT32] 1531 return s.newValue2(ssa.OpComplexMake, n.Type, 1532 s.constFloat32(pt, r.Float32()), 1533 s.constFloat32(pt, i.Float32())) 1534 case 16: 1535 pt := types.Types[TFLOAT64] 1536 return s.newValue2(ssa.OpComplexMake, n.Type, 1537 s.constFloat64(pt, r.Float64()), 1538 s.constFloat64(pt, i.Float64())) 1539 default: 1540 s.Fatalf("bad float size %d", n.Type.Size()) 1541 return nil 1542 } 1543 1544 default: 1545 s.Fatalf("unhandled OLITERAL %v", n.Val().Ctype()) 1546 return nil 1547 } 1548 case OCONVNOP: 1549 to := n.Type 1550 from := n.Left.Type 1551 1552 // Assume everything will work out, so set up our return value. 1553 // Anything interesting that happens from here is a fatal. 1554 x := s.expr(n.Left) 1555 1556 // Special case for not confusing GC and liveness. 1557 // We don't want pointers accidentally classified 1558 // as not-pointers or vice-versa because of copy 1559 // elision. 1560 if to.IsPtrShaped() != from.IsPtrShaped() { 1561 return s.newValue2(ssa.OpConvert, to, x, s.mem()) 1562 } 1563 1564 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type 1565 1566 // CONVNOP closure 1567 if to.Etype == TFUNC && from.IsPtrShaped() { 1568 return v 1569 } 1570 1571 // named <--> unnamed type or typed <--> untyped const 1572 if from.Etype == to.Etype { 1573 return v 1574 } 1575 1576 // unsafe.Pointer <--> *T 1577 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() { 1578 return v 1579 } 1580 1581 dowidth(from) 1582 dowidth(to) 1583 if from.Width != to.Width { 1584 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width) 1585 return nil 1586 } 1587 if etypesign(from.Etype) != etypesign(to.Etype) { 1588 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype) 1589 return nil 1590 } 1591 1592 if instrumenting { 1593 // These appear to be fine, but they fail the 1594 // integer constraint below, so okay them here. 1595 // Sample non-integer conversion: map[string]string -> *uint8 1596 return v 1597 } 1598 1599 if etypesign(from.Etype) == 0 { 1600 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to) 1601 return nil 1602 } 1603 1604 // integer, same width, same sign 1605 return v 1606 1607 case OCONV: 1608 x := s.expr(n.Left) 1609 ft := n.Left.Type // from type 1610 tt := n.Type // to type 1611 if ft.IsBoolean() && tt.IsKind(TUINT8) { 1612 // Bool -> uint8 is generated internally when indexing into runtime.staticbyte. 1613 return s.newValue1(ssa.OpCopy, n.Type, x) 1614 } 1615 if ft.IsInteger() && tt.IsInteger() { 1616 var op ssa.Op 1617 if tt.Size() == ft.Size() { 1618 op = ssa.OpCopy 1619 } else if tt.Size() < ft.Size() { 1620 // truncation 1621 switch 10*ft.Size() + tt.Size() { 1622 case 21: 1623 op = ssa.OpTrunc16to8 1624 case 41: 1625 op = ssa.OpTrunc32to8 1626 case 42: 1627 op = ssa.OpTrunc32to16 1628 case 81: 1629 op = ssa.OpTrunc64to8 1630 case 82: 1631 op = ssa.OpTrunc64to16 1632 case 84: 1633 op = ssa.OpTrunc64to32 1634 default: 1635 s.Fatalf("weird integer truncation %v -> %v", ft, tt) 1636 } 1637 } else if ft.IsSigned() { 1638 // sign extension 1639 switch 10*ft.Size() + tt.Size() { 1640 case 12: 1641 op = ssa.OpSignExt8to16 1642 case 14: 1643 op = ssa.OpSignExt8to32 1644 case 18: 1645 op = ssa.OpSignExt8to64 1646 case 24: 1647 op = ssa.OpSignExt16to32 1648 case 28: 1649 op = ssa.OpSignExt16to64 1650 case 48: 1651 op = ssa.OpSignExt32to64 1652 default: 1653 s.Fatalf("bad integer sign extension %v -> %v", ft, tt) 1654 } 1655 } else { 1656 // zero extension 1657 switch 10*ft.Size() + tt.Size() { 1658 case 12: 1659 op = ssa.OpZeroExt8to16 1660 case 14: 1661 op = ssa.OpZeroExt8to32 1662 case 18: 1663 op = ssa.OpZeroExt8to64 1664 case 24: 1665 op = ssa.OpZeroExt16to32 1666 case 28: 1667 op = ssa.OpZeroExt16to64 1668 case 48: 1669 op = ssa.OpZeroExt32to64 1670 default: 1671 s.Fatalf("weird integer sign extension %v -> %v", ft, tt) 1672 } 1673 } 1674 return s.newValue1(op, n.Type, x) 1675 } 1676 1677 if ft.IsFloat() || tt.IsFloat() { 1678 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}] 1679 if s.config.RegSize == 4 && thearch.LinkArch.Family != sys.MIPS { 1680 if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 { 1681 conv = conv1 1682 } 1683 } 1684 if thearch.LinkArch.Family == sys.ARM64 { 1685 if conv1, ok1 := uint64fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 { 1686 conv = conv1 1687 } 1688 } 1689 1690 if thearch.LinkArch.Family == sys.MIPS { 1691 if ft.Size() == 4 && ft.IsInteger() && !ft.IsSigned() { 1692 // tt is float32 or float64, and ft is also unsigned 1693 if tt.Size() == 4 { 1694 return s.uint32Tofloat32(n, x, ft, tt) 1695 } 1696 if tt.Size() == 8 { 1697 return s.uint32Tofloat64(n, x, ft, tt) 1698 } 1699 } else if tt.Size() == 4 && tt.IsInteger() && !tt.IsSigned() { 1700 // ft is float32 or float64, and tt is unsigned integer 1701 if ft.Size() == 4 { 1702 return s.float32ToUint32(n, x, ft, tt) 1703 } 1704 if ft.Size() == 8 { 1705 return s.float64ToUint32(n, x, ft, tt) 1706 } 1707 } 1708 } 1709 1710 if !ok { 1711 s.Fatalf("weird float conversion %v -> %v", ft, tt) 1712 } 1713 op1, op2, it := conv.op1, conv.op2, conv.intermediateType 1714 1715 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid { 1716 // normal case, not tripping over unsigned 64 1717 if op1 == ssa.OpCopy { 1718 if op2 == ssa.OpCopy { 1719 return x 1720 } 1721 return s.newValue1(op2, n.Type, x) 1722 } 1723 if op2 == ssa.OpCopy { 1724 return s.newValue1(op1, n.Type, x) 1725 } 1726 return s.newValue1(op2, n.Type, s.newValue1(op1, types.Types[it], x)) 1727 } 1728 // Tricky 64-bit unsigned cases. 1729 if ft.IsInteger() { 1730 // tt is float32 or float64, and ft is also unsigned 1731 if tt.Size() == 4 { 1732 return s.uint64Tofloat32(n, x, ft, tt) 1733 } 1734 if tt.Size() == 8 { 1735 return s.uint64Tofloat64(n, x, ft, tt) 1736 } 1737 s.Fatalf("weird unsigned integer to float conversion %v -> %v", ft, tt) 1738 } 1739 // ft is float32 or float64, and tt is unsigned integer 1740 if ft.Size() == 4 { 1741 return s.float32ToUint64(n, x, ft, tt) 1742 } 1743 if ft.Size() == 8 { 1744 return s.float64ToUint64(n, x, ft, tt) 1745 } 1746 s.Fatalf("weird float to unsigned integer conversion %v -> %v", ft, tt) 1747 return nil 1748 } 1749 1750 if ft.IsComplex() && tt.IsComplex() { 1751 var op ssa.Op 1752 if ft.Size() == tt.Size() { 1753 switch ft.Size() { 1754 case 8: 1755 op = ssa.OpRound32F 1756 case 16: 1757 op = ssa.OpRound64F 1758 default: 1759 s.Fatalf("weird complex conversion %v -> %v", ft, tt) 1760 } 1761 } else if ft.Size() == 8 && tt.Size() == 16 { 1762 op = ssa.OpCvt32Fto64F 1763 } else if ft.Size() == 16 && tt.Size() == 8 { 1764 op = ssa.OpCvt64Fto32F 1765 } else { 1766 s.Fatalf("weird complex conversion %v -> %v", ft, tt) 1767 } 1768 ftp := floatForComplex(ft) 1769 ttp := floatForComplex(tt) 1770 return s.newValue2(ssa.OpComplexMake, tt, 1771 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)), 1772 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x))) 1773 } 1774 1775 s.Fatalf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype) 1776 return nil 1777 1778 case ODOTTYPE: 1779 res, _ := s.dottype(n, false) 1780 return res 1781 1782 // binary ops 1783 case OLT, OEQ, ONE, OLE, OGE, OGT: 1784 a := s.expr(n.Left) 1785 b := s.expr(n.Right) 1786 if n.Left.Type.IsComplex() { 1787 pt := floatForComplex(n.Left.Type) 1788 op := s.ssaOp(OEQ, pt) 1789 r := s.newValue2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)) 1790 i := s.newValue2(op, types.Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)) 1791 c := s.newValue2(ssa.OpAndB, types.Types[TBOOL], r, i) 1792 switch n.Op { 1793 case OEQ: 1794 return c 1795 case ONE: 1796 return s.newValue1(ssa.OpNot, types.Types[TBOOL], c) 1797 default: 1798 s.Fatalf("ordered complex compare %v", n.Op) 1799 } 1800 } 1801 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), types.Types[TBOOL], a, b) 1802 case OMUL: 1803 a := s.expr(n.Left) 1804 b := s.expr(n.Right) 1805 if n.Type.IsComplex() { 1806 mulop := ssa.OpMul64F 1807 addop := ssa.OpAdd64F 1808 subop := ssa.OpSub64F 1809 pt := floatForComplex(n.Type) // Could be Float32 or Float64 1810 wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancelation error 1811 1812 areal := s.newValue1(ssa.OpComplexReal, pt, a) 1813 breal := s.newValue1(ssa.OpComplexReal, pt, b) 1814 aimag := s.newValue1(ssa.OpComplexImag, pt, a) 1815 bimag := s.newValue1(ssa.OpComplexImag, pt, b) 1816 1817 if pt != wt { // Widen for calculation 1818 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal) 1819 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal) 1820 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag) 1821 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag) 1822 } 1823 1824 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag)) 1825 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal)) 1826 1827 if pt != wt { // Narrow to store back 1828 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal) 1829 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag) 1830 } 1831 1832 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag) 1833 } 1834 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b) 1835 1836 case ODIV: 1837 a := s.expr(n.Left) 1838 b := s.expr(n.Right) 1839 if n.Type.IsComplex() { 1840 // TODO this is not executed because the front-end substitutes a runtime call. 1841 // That probably ought to change; with modest optimization the widen/narrow 1842 // conversions could all be elided in larger expression trees. 1843 mulop := ssa.OpMul64F 1844 addop := ssa.OpAdd64F 1845 subop := ssa.OpSub64F 1846 divop := ssa.OpDiv64F 1847 pt := floatForComplex(n.Type) // Could be Float32 or Float64 1848 wt := types.Types[TFLOAT64] // Compute in Float64 to minimize cancelation error 1849 1850 areal := s.newValue1(ssa.OpComplexReal, pt, a) 1851 breal := s.newValue1(ssa.OpComplexReal, pt, b) 1852 aimag := s.newValue1(ssa.OpComplexImag, pt, a) 1853 bimag := s.newValue1(ssa.OpComplexImag, pt, b) 1854 1855 if pt != wt { // Widen for calculation 1856 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal) 1857 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal) 1858 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag) 1859 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag) 1860 } 1861 1862 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag)) 1863 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag)) 1864 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag)) 1865 1866 // TODO not sure if this is best done in wide precision or narrow 1867 // Double-rounding might be an issue. 1868 // Note that the pre-SSA implementation does the entire calculation 1869 // in wide format, so wide is compatible. 1870 xreal = s.newValue2(divop, wt, xreal, denom) 1871 ximag = s.newValue2(divop, wt, ximag, denom) 1872 1873 if pt != wt { // Narrow to store back 1874 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal) 1875 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag) 1876 } 1877 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag) 1878 } 1879 if n.Type.IsFloat() { 1880 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b) 1881 } 1882 return s.intDivide(n, a, b) 1883 case OMOD: 1884 a := s.expr(n.Left) 1885 b := s.expr(n.Right) 1886 return s.intDivide(n, a, b) 1887 case OADD, OSUB: 1888 a := s.expr(n.Left) 1889 b := s.expr(n.Right) 1890 if n.Type.IsComplex() { 1891 pt := floatForComplex(n.Type) 1892 op := s.ssaOp(n.Op, pt) 1893 return s.newValue2(ssa.OpComplexMake, n.Type, 1894 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)), 1895 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))) 1896 } 1897 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b) 1898 case OAND, OOR, OXOR: 1899 a := s.expr(n.Left) 1900 b := s.expr(n.Right) 1901 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b) 1902 case OLSH, ORSH: 1903 a := s.expr(n.Left) 1904 b := s.expr(n.Right) 1905 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b) 1906 case OANDAND, OOROR: 1907 // To implement OANDAND (and OOROR), we introduce a 1908 // new temporary variable to hold the result. The 1909 // variable is associated with the OANDAND node in the 1910 // s.vars table (normally variables are only 1911 // associated with ONAME nodes). We convert 1912 // A && B 1913 // to 1914 // var = A 1915 // if var { 1916 // var = B 1917 // } 1918 // Using var in the subsequent block introduces the 1919 // necessary phi variable. 1920 el := s.expr(n.Left) 1921 s.vars[n] = el 1922 1923 b := s.endBlock() 1924 b.Kind = ssa.BlockIf 1925 b.SetControl(el) 1926 // In theory, we should set b.Likely here based on context. 1927 // However, gc only gives us likeliness hints 1928 // in a single place, for plain OIF statements, 1929 // and passing around context is finnicky, so don't bother for now. 1930 1931 bRight := s.f.NewBlock(ssa.BlockPlain) 1932 bResult := s.f.NewBlock(ssa.BlockPlain) 1933 if n.Op == OANDAND { 1934 b.AddEdgeTo(bRight) 1935 b.AddEdgeTo(bResult) 1936 } else if n.Op == OOROR { 1937 b.AddEdgeTo(bResult) 1938 b.AddEdgeTo(bRight) 1939 } 1940 1941 s.startBlock(bRight) 1942 er := s.expr(n.Right) 1943 s.vars[n] = er 1944 1945 b = s.endBlock() 1946 b.AddEdgeTo(bResult) 1947 1948 s.startBlock(bResult) 1949 return s.variable(n, types.Types[TBOOL]) 1950 case OCOMPLEX: 1951 r := s.expr(n.Left) 1952 i := s.expr(n.Right) 1953 return s.newValue2(ssa.OpComplexMake, n.Type, r, i) 1954 1955 // unary ops 1956 case OMINUS: 1957 a := s.expr(n.Left) 1958 if n.Type.IsComplex() { 1959 tp := floatForComplex(n.Type) 1960 negop := s.ssaOp(n.Op, tp) 1961 return s.newValue2(ssa.OpComplexMake, n.Type, 1962 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)), 1963 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a))) 1964 } 1965 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a) 1966 case ONOT, OCOM: 1967 a := s.expr(n.Left) 1968 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a) 1969 case OIMAG, OREAL: 1970 a := s.expr(n.Left) 1971 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a) 1972 case OPLUS: 1973 return s.expr(n.Left) 1974 1975 case OADDR: 1976 return s.addr(n.Left, n.Bounded()) 1977 1978 case OINDREGSP: 1979 addr := s.constOffPtrSP(types.NewPtr(n.Type), n.Xoffset) 1980 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) 1981 1982 case OIND: 1983 p := s.exprPtr(n.Left, false, n.Pos) 1984 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) 1985 1986 case ODOT: 1987 t := n.Left.Type 1988 if canSSAType(t) { 1989 v := s.expr(n.Left) 1990 return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v) 1991 } 1992 if n.Left.Op == OSTRUCTLIT { 1993 // All literals with nonzero fields have already been 1994 // rewritten during walk. Any that remain are just T{} 1995 // or equivalents. Use the zero value. 1996 if !iszero(n.Left) { 1997 Fatalf("literal with nonzero value in SSA: %v", n.Left) 1998 } 1999 return s.zeroVal(n.Type) 2000 } 2001 p := s.addr(n, false) 2002 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) 2003 2004 case ODOTPTR: 2005 p := s.exprPtr(n.Left, false, n.Pos) 2006 p = s.newValue1I(ssa.OpOffPtr, types.NewPtr(n.Type), n.Xoffset, p) 2007 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) 2008 2009 case OINDEX: 2010 switch { 2011 case n.Left.Type.IsString(): 2012 if n.Bounded() && Isconst(n.Left, CTSTR) && Isconst(n.Right, CTINT) { 2013 // Replace "abc"[1] with 'b'. 2014 // Delayed until now because "abc"[1] is not an ideal constant. 2015 // See test/fixedbugs/issue11370.go. 2016 return s.newValue0I(ssa.OpConst8, types.Types[TUINT8], int64(int8(n.Left.Val().U.(string)[n.Right.Int64()]))) 2017 } 2018 a := s.expr(n.Left) 2019 i := s.expr(n.Right) 2020 i = s.extendIndex(i, panicindex) 2021 if !n.Bounded() { 2022 len := s.newValue1(ssa.OpStringLen, types.Types[TINT], a) 2023 s.boundsCheck(i, len) 2024 } 2025 ptrtyp := s.f.Config.Types.BytePtr 2026 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a) 2027 if Isconst(n.Right, CTINT) { 2028 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr) 2029 } else { 2030 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i) 2031 } 2032 return s.newValue2(ssa.OpLoad, types.Types[TUINT8], ptr, s.mem()) 2033 case n.Left.Type.IsSlice(): 2034 p := s.addr(n, false) 2035 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem()) 2036 case n.Left.Type.IsArray(): 2037 if bound := n.Left.Type.NumElem(); bound <= 1 { 2038 // SSA can handle arrays of length at most 1. 2039 a := s.expr(n.Left) 2040 i := s.expr(n.Right) 2041 if bound == 0 { 2042 // Bounds check will never succeed. Might as well 2043 // use constants for the bounds check. 2044 z := s.constInt(types.Types[TINT], 0) 2045 s.boundsCheck(z, z) 2046 // The return value won't be live, return junk. 2047 return s.newValue0(ssa.OpUnknown, n.Type) 2048 } 2049 i = s.extendIndex(i, panicindex) 2050 if !n.Bounded() { 2051 s.boundsCheck(i, s.constInt(types.Types[TINT], bound)) 2052 } 2053 return s.newValue1I(ssa.OpArraySelect, n.Type, 0, a) 2054 } 2055 p := s.addr(n, false) 2056 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem()) 2057 default: 2058 s.Fatalf("bad type for index %v", n.Left.Type) 2059 return nil 2060 } 2061 2062 case OLEN, OCAP: 2063 switch { 2064 case n.Left.Type.IsSlice(): 2065 op := ssa.OpSliceLen 2066 if n.Op == OCAP { 2067 op = ssa.OpSliceCap 2068 } 2069 return s.newValue1(op, types.Types[TINT], s.expr(n.Left)) 2070 case n.Left.Type.IsString(): // string; not reachable for OCAP 2071 return s.newValue1(ssa.OpStringLen, types.Types[TINT], s.expr(n.Left)) 2072 case n.Left.Type.IsMap(), n.Left.Type.IsChan(): 2073 return s.referenceTypeBuiltin(n, s.expr(n.Left)) 2074 default: // array 2075 return s.constInt(types.Types[TINT], n.Left.Type.NumElem()) 2076 } 2077 2078 case OSPTR: 2079 a := s.expr(n.Left) 2080 if n.Left.Type.IsSlice() { 2081 return s.newValue1(ssa.OpSlicePtr, n.Type, a) 2082 } else { 2083 return s.newValue1(ssa.OpStringPtr, n.Type, a) 2084 } 2085 2086 case OITAB: 2087 a := s.expr(n.Left) 2088 return s.newValue1(ssa.OpITab, n.Type, a) 2089 2090 case OIDATA: 2091 a := s.expr(n.Left) 2092 return s.newValue1(ssa.OpIData, n.Type, a) 2093 2094 case OEFACE: 2095 tab := s.expr(n.Left) 2096 data := s.expr(n.Right) 2097 return s.newValue2(ssa.OpIMake, n.Type, tab, data) 2098 2099 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR: 2100 v := s.expr(n.Left) 2101 var i, j, k *ssa.Value 2102 low, high, max := n.SliceBounds() 2103 if low != nil { 2104 i = s.extendIndex(s.expr(low), panicslice) 2105 } 2106 if high != nil { 2107 j = s.extendIndex(s.expr(high), panicslice) 2108 } 2109 if max != nil { 2110 k = s.extendIndex(s.expr(max), panicslice) 2111 } 2112 p, l, c := s.slice(n.Left.Type, v, i, j, k) 2113 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c) 2114 2115 case OSLICESTR: 2116 v := s.expr(n.Left) 2117 var i, j *ssa.Value 2118 low, high, _ := n.SliceBounds() 2119 if low != nil { 2120 i = s.extendIndex(s.expr(low), panicslice) 2121 } 2122 if high != nil { 2123 j = s.extendIndex(s.expr(high), panicslice) 2124 } 2125 p, l, _ := s.slice(n.Left.Type, v, i, j, nil) 2126 return s.newValue2(ssa.OpStringMake, n.Type, p, l) 2127 2128 case OCALLFUNC: 2129 if isIntrinsicCall(n) { 2130 return s.intrinsicCall(n) 2131 } 2132 fallthrough 2133 2134 case OCALLINTER, OCALLMETH: 2135 a := s.call(n, callNormal) 2136 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem()) 2137 2138 case OGETG: 2139 return s.newValue1(ssa.OpGetG, n.Type, s.mem()) 2140 2141 case OAPPEND: 2142 return s.append(n, false) 2143 2144 case OSTRUCTLIT, OARRAYLIT: 2145 // All literals with nonzero fields have already been 2146 // rewritten during walk. Any that remain are just T{} 2147 // or equivalents. Use the zero value. 2148 if !iszero(n) { 2149 Fatalf("literal with nonzero value in SSA: %v", n) 2150 } 2151 return s.zeroVal(n.Type) 2152 2153 default: 2154 s.Fatalf("unhandled expr %v", n.Op) 2155 return nil 2156 } 2157 } 2158 2159 // append converts an OAPPEND node to SSA. 2160 // If inplace is false, it converts the OAPPEND expression n to an ssa.Value, 2161 // adds it to s, and returns the Value. 2162 // If inplace is true, it writes the result of the OAPPEND expression n 2163 // back to the slice being appended to, and returns nil. 2164 // inplace MUST be set to false if the slice can be SSA'd. 2165 func (s *state) append(n *Node, inplace bool) *ssa.Value { 2166 // If inplace is false, process as expression "append(s, e1, e2, e3)": 2167 // 2168 // ptr, len, cap := s 2169 // newlen := len + 3 2170 // if newlen > cap { 2171 // ptr, len, cap = growslice(s, newlen) 2172 // newlen = len + 3 // recalculate to avoid a spill 2173 // } 2174 // // with write barriers, if needed: 2175 // *(ptr+len) = e1 2176 // *(ptr+len+1) = e2 2177 // *(ptr+len+2) = e3 2178 // return makeslice(ptr, newlen, cap) 2179 // 2180 // 2181 // If inplace is true, process as statement "s = append(s, e1, e2, e3)": 2182 // 2183 // a := &s 2184 // ptr, len, cap := s 2185 // newlen := len + 3 2186 // if newlen > cap { 2187 // newptr, len, newcap = growslice(ptr, len, cap, newlen) 2188 // vardef(a) // if necessary, advise liveness we are writing a new a 2189 // *a.cap = newcap // write before ptr to avoid a spill 2190 // *a.ptr = newptr // with write barrier 2191 // } 2192 // newlen = len + 3 // recalculate to avoid a spill 2193 // *a.len = newlen 2194 // // with write barriers, if needed: 2195 // *(ptr+len) = e1 2196 // *(ptr+len+1) = e2 2197 // *(ptr+len+2) = e3 2198 2199 et := n.Type.Elem() 2200 pt := types.NewPtr(et) 2201 2202 // Evaluate slice 2203 sn := n.List.First() // the slice node is the first in the list 2204 2205 var slice, addr *ssa.Value 2206 if inplace { 2207 addr = s.addr(sn, false) 2208 slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) 2209 } else { 2210 slice = s.expr(sn) 2211 } 2212 2213 // Allocate new blocks 2214 grow := s.f.NewBlock(ssa.BlockPlain) 2215 assign := s.f.NewBlock(ssa.BlockPlain) 2216 2217 // Decide if we need to grow 2218 nargs := int64(n.List.Len() - 1) 2219 p := s.newValue1(ssa.OpSlicePtr, pt, slice) 2220 l := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice) 2221 c := s.newValue1(ssa.OpSliceCap, types.Types[TINT], slice) 2222 nl := s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs)) 2223 2224 cmp := s.newValue2(s.ssaOp(OGT, types.Types[TINT]), types.Types[TBOOL], nl, c) 2225 s.vars[&ptrVar] = p 2226 2227 if !inplace { 2228 s.vars[&newlenVar] = nl 2229 s.vars[&capVar] = c 2230 } else { 2231 s.vars[&lenVar] = l 2232 } 2233 2234 b := s.endBlock() 2235 b.Kind = ssa.BlockIf 2236 b.Likely = ssa.BranchUnlikely 2237 b.SetControl(cmp) 2238 b.AddEdgeTo(grow) 2239 b.AddEdgeTo(assign) 2240 2241 // Call growslice 2242 s.startBlock(grow) 2243 taddr := s.expr(n.Left) 2244 r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.Types[TINT]}, taddr, p, l, c, nl) 2245 2246 if inplace { 2247 if sn.Op == ONAME && sn.Class() != PEXTERN { 2248 // Tell liveness we're about to build a new slice 2249 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem()) 2250 } 2251 capaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, int64(array_cap), addr) 2252 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], capaddr, r[2], s.mem()) 2253 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, pt, addr, r[0], s.mem()) 2254 // load the value we just stored to avoid having to spill it 2255 s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem()) 2256 s.vars[&lenVar] = r[1] // avoid a spill in the fast path 2257 } else { 2258 s.vars[&ptrVar] = r[0] 2259 s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], r[1], s.constInt(types.Types[TINT], nargs)) 2260 s.vars[&capVar] = r[2] 2261 } 2262 2263 b = s.endBlock() 2264 b.AddEdgeTo(assign) 2265 2266 // assign new elements to slots 2267 s.startBlock(assign) 2268 2269 if inplace { 2270 l = s.variable(&lenVar, types.Types[TINT]) // generates phi for len 2271 nl = s.newValue2(s.ssaOp(OADD, types.Types[TINT]), types.Types[TINT], l, s.constInt(types.Types[TINT], nargs)) 2272 lenaddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, int64(array_nel), addr) 2273 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], lenaddr, nl, s.mem()) 2274 } 2275 2276 // Evaluate args 2277 type argRec struct { 2278 // if store is true, we're appending the value v. If false, we're appending the 2279 // value at *v. 2280 v *ssa.Value 2281 store bool 2282 } 2283 args := make([]argRec, 0, nargs) 2284 for _, n := range n.List.Slice()[1:] { 2285 if canSSAType(n.Type) { 2286 args = append(args, argRec{v: s.expr(n), store: true}) 2287 } else { 2288 v := s.addr(n, false) 2289 args = append(args, argRec{v: v}) 2290 } 2291 } 2292 2293 p = s.variable(&ptrVar, pt) // generates phi for ptr 2294 if !inplace { 2295 nl = s.variable(&newlenVar, types.Types[TINT]) // generates phi for nl 2296 c = s.variable(&capVar, types.Types[TINT]) // generates phi for cap 2297 } 2298 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l) 2299 for i, arg := range args { 2300 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(types.Types[TINT], int64(i))) 2301 if arg.store { 2302 s.storeType(et, addr, arg.v, 0) 2303 } else { 2304 store := s.newValue3I(ssa.OpMove, types.TypeMem, et.Size(), addr, arg.v, s.mem()) 2305 store.Aux = et 2306 s.vars[&memVar] = store 2307 } 2308 } 2309 2310 delete(s.vars, &ptrVar) 2311 if inplace { 2312 delete(s.vars, &lenVar) 2313 return nil 2314 } 2315 delete(s.vars, &newlenVar) 2316 delete(s.vars, &capVar) 2317 // make result 2318 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c) 2319 } 2320 2321 // condBranch evaluates the boolean expression cond and branches to yes 2322 // if cond is true and no if cond is false. 2323 // This function is intended to handle && and || better than just calling 2324 // s.expr(cond) and branching on the result. 2325 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) { 2326 if cond.Op == OANDAND { 2327 mid := s.f.NewBlock(ssa.BlockPlain) 2328 s.stmtList(cond.Ninit) 2329 s.condBranch(cond.Left, mid, no, max8(likely, 0)) 2330 s.startBlock(mid) 2331 s.condBranch(cond.Right, yes, no, likely) 2332 return 2333 // Note: if likely==1, then both recursive calls pass 1. 2334 // If likely==-1, then we don't have enough information to decide 2335 // whether the first branch is likely or not. So we pass 0 for 2336 // the likeliness of the first branch. 2337 // TODO: have the frontend give us branch prediction hints for 2338 // OANDAND and OOROR nodes (if it ever has such info). 2339 } 2340 if cond.Op == OOROR { 2341 mid := s.f.NewBlock(ssa.BlockPlain) 2342 s.stmtList(cond.Ninit) 2343 s.condBranch(cond.Left, yes, mid, min8(likely, 0)) 2344 s.startBlock(mid) 2345 s.condBranch(cond.Right, yes, no, likely) 2346 return 2347 // Note: if likely==-1, then both recursive calls pass -1. 2348 // If likely==1, then we don't have enough info to decide 2349 // the likelihood of the first branch. 2350 } 2351 if cond.Op == ONOT { 2352 s.stmtList(cond.Ninit) 2353 s.condBranch(cond.Left, no, yes, -likely) 2354 return 2355 } 2356 c := s.expr(cond) 2357 b := s.endBlock() 2358 b.Kind = ssa.BlockIf 2359 b.SetControl(c) 2360 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness 2361 b.AddEdgeTo(yes) 2362 b.AddEdgeTo(no) 2363 } 2364 2365 type skipMask uint8 2366 2367 const ( 2368 skipPtr skipMask = 1 << iota 2369 skipLen 2370 skipCap 2371 ) 2372 2373 // assign does left = right. 2374 // Right has already been evaluated to ssa, left has not. 2375 // If deref is true, then we do left = *right instead (and right has already been nil-checked). 2376 // If deref is true and right == nil, just do left = 0. 2377 // skip indicates assignments (at the top level) that can be avoided. 2378 func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) { 2379 if left.Op == ONAME && isblank(left) { 2380 return 2381 } 2382 t := left.Type 2383 dowidth(t) 2384 if s.canSSA(left) { 2385 if deref { 2386 s.Fatalf("can SSA LHS %v but not RHS %s", left, right) 2387 } 2388 if left.Op == ODOT { 2389 // We're assigning to a field of an ssa-able value. 2390 // We need to build a new structure with the new value for the 2391 // field we're assigning and the old values for the other fields. 2392 // For instance: 2393 // type T struct {a, b, c int} 2394 // var T x 2395 // x.b = 5 2396 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c} 2397 2398 // Grab information about the structure type. 2399 t := left.Left.Type 2400 nf := t.NumFields() 2401 idx := fieldIdx(left) 2402 2403 // Grab old value of structure. 2404 old := s.expr(left.Left) 2405 2406 // Make new structure. 2407 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t) 2408 2409 // Add fields as args. 2410 for i := 0; i < nf; i++ { 2411 if i == idx { 2412 new.AddArg(right) 2413 } else { 2414 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old)) 2415 } 2416 } 2417 2418 // Recursively assign the new value we've made to the base of the dot op. 2419 s.assign(left.Left, new, false, 0) 2420 // TODO: do we need to update named values here? 2421 return 2422 } 2423 if left.Op == OINDEX && left.Left.Type.IsArray() { 2424 // We're assigning to an element of an ssa-able array. 2425 // a[i] = v 2426 t := left.Left.Type 2427 n := t.NumElem() 2428 2429 i := s.expr(left.Right) // index 2430 if n == 0 { 2431 // The bounds check must fail. Might as well 2432 // ignore the actual index and just use zeros. 2433 z := s.constInt(types.Types[TINT], 0) 2434 s.boundsCheck(z, z) 2435 return 2436 } 2437 if n != 1 { 2438 s.Fatalf("assigning to non-1-length array") 2439 } 2440 // Rewrite to a = [1]{v} 2441 i = s.extendIndex(i, panicindex) 2442 s.boundsCheck(i, s.constInt(types.Types[TINT], 1)) 2443 v := s.newValue1(ssa.OpArrayMake1, t, right) 2444 s.assign(left.Left, v, false, 0) 2445 return 2446 } 2447 // Update variable assignment. 2448 s.vars[left] = right 2449 s.addNamedValue(left, right) 2450 return 2451 } 2452 // Left is not ssa-able. Compute its address. 2453 addr := s.addr(left, false) 2454 if left.Op == ONAME && left.Class() != PEXTERN && skip == 0 { 2455 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, left, s.mem()) 2456 } 2457 if isReflectHeaderDataField(left) { 2458 // Package unsafe's documentation says storing pointers into 2459 // reflect.SliceHeader and reflect.StringHeader's Data fields 2460 // is valid, even though they have type uintptr (#19168). 2461 // Mark it pointer type to signal the writebarrier pass to 2462 // insert a write barrier. 2463 t = types.Types[TUNSAFEPTR] 2464 } 2465 if deref { 2466 // Treat as a mem->mem move. 2467 var store *ssa.Value 2468 if right == nil { 2469 store = s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), addr, s.mem()) 2470 } else { 2471 store = s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), addr, right, s.mem()) 2472 } 2473 store.Aux = t 2474 s.vars[&memVar] = store 2475 return 2476 } 2477 // Treat as a store. 2478 s.storeType(t, addr, right, skip) 2479 } 2480 2481 // zeroVal returns the zero value for type t. 2482 func (s *state) zeroVal(t *types.Type) *ssa.Value { 2483 switch { 2484 case t.IsInteger(): 2485 switch t.Size() { 2486 case 1: 2487 return s.constInt8(t, 0) 2488 case 2: 2489 return s.constInt16(t, 0) 2490 case 4: 2491 return s.constInt32(t, 0) 2492 case 8: 2493 return s.constInt64(t, 0) 2494 default: 2495 s.Fatalf("bad sized integer type %v", t) 2496 } 2497 case t.IsFloat(): 2498 switch t.Size() { 2499 case 4: 2500 return s.constFloat32(t, 0) 2501 case 8: 2502 return s.constFloat64(t, 0) 2503 default: 2504 s.Fatalf("bad sized float type %v", t) 2505 } 2506 case t.IsComplex(): 2507 switch t.Size() { 2508 case 8: 2509 z := s.constFloat32(types.Types[TFLOAT32], 0) 2510 return s.entryNewValue2(ssa.OpComplexMake, t, z, z) 2511 case 16: 2512 z := s.constFloat64(types.Types[TFLOAT64], 0) 2513 return s.entryNewValue2(ssa.OpComplexMake, t, z, z) 2514 default: 2515 s.Fatalf("bad sized complex type %v", t) 2516 } 2517 2518 case t.IsString(): 2519 return s.constEmptyString(t) 2520 case t.IsPtrShaped(): 2521 return s.constNil(t) 2522 case t.IsBoolean(): 2523 return s.constBool(false) 2524 case t.IsInterface(): 2525 return s.constInterface(t) 2526 case t.IsSlice(): 2527 return s.constSlice(t) 2528 case t.IsStruct(): 2529 n := t.NumFields() 2530 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t) 2531 for i := 0; i < n; i++ { 2532 v.AddArg(s.zeroVal(t.FieldType(i))) 2533 } 2534 return v 2535 case t.IsArray(): 2536 switch t.NumElem() { 2537 case 0: 2538 return s.entryNewValue0(ssa.OpArrayMake0, t) 2539 case 1: 2540 return s.entryNewValue1(ssa.OpArrayMake1, t, s.zeroVal(t.Elem())) 2541 } 2542 } 2543 s.Fatalf("zero for type %v not implemented", t) 2544 return nil 2545 } 2546 2547 type callKind int8 2548 2549 const ( 2550 callNormal callKind = iota 2551 callDefer 2552 callGo 2553 ) 2554 2555 var intrinsics map[intrinsicKey]intrinsicBuilder 2556 2557 // An intrinsicBuilder converts a call node n into an ssa value that 2558 // implements that call as an intrinsic. args is a list of arguments to the func. 2559 type intrinsicBuilder func(s *state, n *Node, args []*ssa.Value) *ssa.Value 2560 2561 type intrinsicKey struct { 2562 arch *sys.Arch 2563 pkg string 2564 fn string 2565 } 2566 2567 func init() { 2568 intrinsics = map[intrinsicKey]intrinsicBuilder{} 2569 2570 var all []*sys.Arch 2571 var p4 []*sys.Arch 2572 var p8 []*sys.Arch 2573 for _, a := range sys.Archs { 2574 all = append(all, a) 2575 if a.PtrSize == 4 { 2576 p4 = append(p4, a) 2577 } else { 2578 p8 = append(p8, a) 2579 } 2580 } 2581 2582 // add adds the intrinsic b for pkg.fn for the given list of architectures. 2583 add := func(pkg, fn string, b intrinsicBuilder, archs ...*sys.Arch) { 2584 for _, a := range archs { 2585 intrinsics[intrinsicKey{a, pkg, fn}] = b 2586 } 2587 } 2588 // addF does the same as add but operates on architecture families. 2589 addF := func(pkg, fn string, b intrinsicBuilder, archFamilies ...sys.ArchFamily) { 2590 m := 0 2591 for _, f := range archFamilies { 2592 if f >= 32 { 2593 panic("too many architecture families") 2594 } 2595 m |= 1 << uint(f) 2596 } 2597 for _, a := range all { 2598 if m>>uint(a.Family)&1 != 0 { 2599 intrinsics[intrinsicKey{a, pkg, fn}] = b 2600 } 2601 } 2602 } 2603 // alias defines pkg.fn = pkg2.fn2 for all architectures in archs for which pkg2.fn2 exists. 2604 alias := func(pkg, fn, pkg2, fn2 string, archs ...*sys.Arch) { 2605 for _, a := range archs { 2606 if b, ok := intrinsics[intrinsicKey{a, pkg2, fn2}]; ok { 2607 intrinsics[intrinsicKey{a, pkg, fn}] = b 2608 } 2609 } 2610 } 2611 2612 /******** runtime ********/ 2613 if !instrumenting { 2614 add("runtime", "slicebytetostringtmp", 2615 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2616 // Compiler frontend optimizations emit OARRAYBYTESTRTMP nodes 2617 // for the backend instead of slicebytetostringtmp calls 2618 // when not instrumenting. 2619 slice := args[0] 2620 ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, slice) 2621 len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], slice) 2622 return s.newValue2(ssa.OpStringMake, n.Type, ptr, len) 2623 }, 2624 all...) 2625 } 2626 add("runtime", "KeepAlive", 2627 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2628 data := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, args[0]) 2629 s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, types.TypeMem, data, s.mem()) 2630 return nil 2631 }, 2632 all...) 2633 add("runtime", "getclosureptr", 2634 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2635 return s.newValue0(ssa.OpGetClosurePtr, s.f.Config.Types.Uintptr) 2636 }, 2637 all...) 2638 2639 addF("runtime", "getcallerpc", 2640 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2641 return s.newValue0(ssa.OpGetCallerPC, s.f.Config.Types.Uintptr) 2642 }, sys.AMD64, sys.I386) 2643 2644 add("runtime", "getcallersp", 2645 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2646 return s.newValue0(ssa.OpGetCallerSP, s.f.Config.Types.Uintptr) 2647 }, 2648 all...) 2649 2650 /******** runtime/internal/sys ********/ 2651 addF("runtime/internal/sys", "Ctz32", 2652 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2653 return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0]) 2654 }, 2655 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS) 2656 addF("runtime/internal/sys", "Ctz64", 2657 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2658 return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0]) 2659 }, 2660 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS) 2661 addF("runtime/internal/sys", "Bswap32", 2662 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2663 return s.newValue1(ssa.OpBswap32, types.Types[TUINT32], args[0]) 2664 }, 2665 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X) 2666 addF("runtime/internal/sys", "Bswap64", 2667 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2668 return s.newValue1(ssa.OpBswap64, types.Types[TUINT64], args[0]) 2669 }, 2670 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X) 2671 2672 /******** runtime/internal/atomic ********/ 2673 addF("runtime/internal/atomic", "Load", 2674 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2675 v := s.newValue2(ssa.OpAtomicLoad32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], s.mem()) 2676 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2677 return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v) 2678 }, 2679 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2680 addF("runtime/internal/atomic", "Load64", 2681 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2682 v := s.newValue2(ssa.OpAtomicLoad64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], s.mem()) 2683 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2684 return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v) 2685 }, 2686 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) 2687 addF("runtime/internal/atomic", "Loadp", 2688 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2689 v := s.newValue2(ssa.OpAtomicLoadPtr, types.NewTuple(s.f.Config.Types.BytePtr, types.TypeMem), args[0], s.mem()) 2690 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2691 return s.newValue1(ssa.OpSelect0, s.f.Config.Types.BytePtr, v) 2692 }, 2693 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2694 2695 addF("runtime/internal/atomic", "Store", 2696 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2697 s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore32, types.TypeMem, args[0], args[1], s.mem()) 2698 return nil 2699 }, 2700 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2701 addF("runtime/internal/atomic", "Store64", 2702 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2703 s.vars[&memVar] = s.newValue3(ssa.OpAtomicStore64, types.TypeMem, args[0], args[1], s.mem()) 2704 return nil 2705 }, 2706 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) 2707 addF("runtime/internal/atomic", "StorepNoWB", 2708 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2709 s.vars[&memVar] = s.newValue3(ssa.OpAtomicStorePtrNoWB, types.TypeMem, args[0], args[1], s.mem()) 2710 return nil 2711 }, 2712 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64) 2713 2714 addF("runtime/internal/atomic", "Xchg", 2715 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2716 v := s.newValue3(ssa.OpAtomicExchange32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem()) 2717 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2718 return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v) 2719 }, 2720 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2721 addF("runtime/internal/atomic", "Xchg64", 2722 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2723 v := s.newValue3(ssa.OpAtomicExchange64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem()) 2724 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2725 return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v) 2726 }, 2727 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) 2728 2729 addF("runtime/internal/atomic", "Xadd", 2730 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2731 v := s.newValue3(ssa.OpAtomicAdd32, types.NewTuple(types.Types[TUINT32], types.TypeMem), args[0], args[1], s.mem()) 2732 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2733 return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v) 2734 }, 2735 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2736 addF("runtime/internal/atomic", "Xadd64", 2737 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2738 v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem()) 2739 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2740 return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v) 2741 }, 2742 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) 2743 2744 addF("runtime/internal/atomic", "Cas", 2745 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2746 v := s.newValue4(ssa.OpAtomicCompareAndSwap32, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem()) 2747 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2748 return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v) 2749 }, 2750 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64) 2751 addF("runtime/internal/atomic", "Cas64", 2752 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2753 v := s.newValue4(ssa.OpAtomicCompareAndSwap64, types.NewTuple(types.Types[TBOOL], types.TypeMem), args[0], args[1], args[2], s.mem()) 2754 s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v) 2755 return s.newValue1(ssa.OpSelect0, types.Types[TBOOL], v) 2756 }, 2757 sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64) 2758 2759 addF("runtime/internal/atomic", "And8", 2760 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2761 s.vars[&memVar] = s.newValue3(ssa.OpAtomicAnd8, types.TypeMem, args[0], args[1], s.mem()) 2762 return nil 2763 }, 2764 sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64) 2765 addF("runtime/internal/atomic", "Or8", 2766 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2767 s.vars[&memVar] = s.newValue3(ssa.OpAtomicOr8, types.TypeMem, args[0], args[1], s.mem()) 2768 return nil 2769 }, 2770 sys.AMD64, sys.ARM64, sys.MIPS, sys.PPC64) 2771 2772 alias("runtime/internal/atomic", "Loadint64", "runtime/internal/atomic", "Load64", all...) 2773 alias("runtime/internal/atomic", "Xaddint64", "runtime/internal/atomic", "Xadd64", all...) 2774 alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load", p4...) 2775 alias("runtime/internal/atomic", "Loaduint", "runtime/internal/atomic", "Load64", p8...) 2776 alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load", p4...) 2777 alias("runtime/internal/atomic", "Loaduintptr", "runtime/internal/atomic", "Load64", p8...) 2778 alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store", p4...) 2779 alias("runtime/internal/atomic", "Storeuintptr", "runtime/internal/atomic", "Store64", p8...) 2780 alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg", p4...) 2781 alias("runtime/internal/atomic", "Xchguintptr", "runtime/internal/atomic", "Xchg64", p8...) 2782 alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd", p4...) 2783 alias("runtime/internal/atomic", "Xadduintptr", "runtime/internal/atomic", "Xadd64", p8...) 2784 alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas", p4...) 2785 alias("runtime/internal/atomic", "Casuintptr", "runtime/internal/atomic", "Cas64", p8...) 2786 alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas", p4...) 2787 alias("runtime/internal/atomic", "Casp1", "runtime/internal/atomic", "Cas64", p8...) 2788 2789 /******** math ********/ 2790 addF("math", "Sqrt", 2791 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2792 return s.newValue1(ssa.OpSqrt, types.Types[TFLOAT64], args[0]) 2793 }, 2794 sys.AMD64, sys.ARM, sys.ARM64, sys.MIPS, sys.PPC64, sys.S390X) 2795 addF("math", "Trunc", 2796 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2797 return s.newValue1(ssa.OpTrunc, types.Types[TFLOAT64], args[0]) 2798 }, 2799 sys.PPC64, sys.S390X) 2800 addF("math", "Ceil", 2801 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2802 return s.newValue1(ssa.OpCeil, types.Types[TFLOAT64], args[0]) 2803 }, 2804 sys.PPC64, sys.S390X) 2805 addF("math", "Floor", 2806 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2807 return s.newValue1(ssa.OpFloor, types.Types[TFLOAT64], args[0]) 2808 }, 2809 sys.PPC64, sys.S390X) 2810 addF("math", "Round", 2811 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2812 return s.newValue1(ssa.OpRound, types.Types[TFLOAT64], args[0]) 2813 }, 2814 sys.S390X) 2815 2816 /******** math/bits ********/ 2817 addF("math/bits", "TrailingZeros64", 2818 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2819 return s.newValue1(ssa.OpCtz64, types.Types[TINT], args[0]) 2820 }, 2821 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2822 addF("math/bits", "TrailingZeros32", 2823 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2824 return s.newValue1(ssa.OpCtz32, types.Types[TINT], args[0]) 2825 }, 2826 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2827 addF("math/bits", "TrailingZeros16", 2828 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2829 x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0]) 2830 c := s.constInt32(types.Types[TUINT32], 1<<16) 2831 y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c) 2832 return s.newValue1(ssa.OpCtz32, types.Types[TINT], y) 2833 }, 2834 sys.ARM, sys.MIPS) 2835 addF("math/bits", "TrailingZeros16", 2836 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2837 x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0]) 2838 c := s.constInt64(types.Types[TUINT64], 1<<16) 2839 y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c) 2840 return s.newValue1(ssa.OpCtz64, types.Types[TINT], y) 2841 }, 2842 sys.AMD64, sys.ARM64, sys.S390X) 2843 addF("math/bits", "TrailingZeros8", 2844 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2845 x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0]) 2846 c := s.constInt32(types.Types[TUINT32], 1<<8) 2847 y := s.newValue2(ssa.OpOr32, types.Types[TUINT32], x, c) 2848 return s.newValue1(ssa.OpCtz32, types.Types[TINT], y) 2849 }, 2850 sys.ARM, sys.MIPS) 2851 addF("math/bits", "TrailingZeros8", 2852 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2853 x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0]) 2854 c := s.constInt64(types.Types[TUINT64], 1<<8) 2855 y := s.newValue2(ssa.OpOr64, types.Types[TUINT64], x, c) 2856 return s.newValue1(ssa.OpCtz64, types.Types[TINT], y) 2857 }, 2858 sys.AMD64, sys.ARM64, sys.S390X) 2859 alias("math/bits", "ReverseBytes64", "runtime/internal/sys", "Bswap64", all...) 2860 alias("math/bits", "ReverseBytes32", "runtime/internal/sys", "Bswap32", all...) 2861 // ReverseBytes inlines correctly, no need to intrinsify it. 2862 // ReverseBytes16 lowers to a rotate, no need for anything special here. 2863 addF("math/bits", "Len64", 2864 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2865 return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0]) 2866 }, 2867 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2868 addF("math/bits", "Len32", 2869 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2870 if s.config.PtrSize == 4 { 2871 return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0]) 2872 } 2873 x := s.newValue1(ssa.OpZeroExt32to64, types.Types[TUINT64], args[0]) 2874 return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x) 2875 }, 2876 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2877 addF("math/bits", "Len16", 2878 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2879 if s.config.PtrSize == 4 { 2880 x := s.newValue1(ssa.OpZeroExt16to32, types.Types[TUINT32], args[0]) 2881 return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x) 2882 } 2883 x := s.newValue1(ssa.OpZeroExt16to64, types.Types[TUINT64], args[0]) 2884 return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x) 2885 }, 2886 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2887 // Note: disabled on AMD64 because the Go code is faster! 2888 addF("math/bits", "Len8", 2889 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2890 if s.config.PtrSize == 4 { 2891 x := s.newValue1(ssa.OpZeroExt8to32, types.Types[TUINT32], args[0]) 2892 return s.newValue1(ssa.OpBitLen32, types.Types[TINT], x) 2893 } 2894 x := s.newValue1(ssa.OpZeroExt8to64, types.Types[TUINT64], args[0]) 2895 return s.newValue1(ssa.OpBitLen64, types.Types[TINT], x) 2896 }, 2897 sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2898 2899 addF("math/bits", "Len", 2900 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2901 if s.config.PtrSize == 4 { 2902 return s.newValue1(ssa.OpBitLen32, types.Types[TINT], args[0]) 2903 } 2904 return s.newValue1(ssa.OpBitLen64, types.Types[TINT], args[0]) 2905 }, 2906 sys.AMD64, sys.ARM64, sys.ARM, sys.S390X, sys.MIPS, sys.PPC64) 2907 // LeadingZeros is handled because it trivially calls Len. 2908 addF("math/bits", "Reverse64", 2909 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2910 return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0]) 2911 }, 2912 sys.ARM64) 2913 addF("math/bits", "Reverse32", 2914 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2915 return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0]) 2916 }, 2917 sys.ARM64) 2918 addF("math/bits", "Reverse16", 2919 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2920 return s.newValue1(ssa.OpBitRev16, types.Types[TINT], args[0]) 2921 }, 2922 sys.ARM64) 2923 addF("math/bits", "Reverse8", 2924 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2925 return s.newValue1(ssa.OpBitRev8, types.Types[TINT], args[0]) 2926 }, 2927 sys.ARM64) 2928 addF("math/bits", "Reverse", 2929 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2930 if s.config.PtrSize == 4 { 2931 return s.newValue1(ssa.OpBitRev32, types.Types[TINT], args[0]) 2932 } 2933 return s.newValue1(ssa.OpBitRev64, types.Types[TINT], args[0]) 2934 }, 2935 sys.ARM64) 2936 makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2937 return func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2938 aux := syslook("support_popcnt").Sym.Linksym() 2939 addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), aux, s.sb) 2940 v := s.newValue2(ssa.OpLoad, types.Types[TBOOL], addr, s.mem()) 2941 b := s.endBlock() 2942 b.Kind = ssa.BlockIf 2943 b.SetControl(v) 2944 bTrue := s.f.NewBlock(ssa.BlockPlain) 2945 bFalse := s.f.NewBlock(ssa.BlockPlain) 2946 bEnd := s.f.NewBlock(ssa.BlockPlain) 2947 b.AddEdgeTo(bTrue) 2948 b.AddEdgeTo(bFalse) 2949 b.Likely = ssa.BranchLikely // most machines have popcnt nowadays 2950 2951 // We have the intrinsic - use it directly. 2952 s.startBlock(bTrue) 2953 op := op64 2954 if s.config.PtrSize == 4 { 2955 op = op32 2956 } 2957 s.vars[n] = s.newValue1(op, types.Types[TINT], args[0]) 2958 s.endBlock().AddEdgeTo(bEnd) 2959 2960 // Call the pure Go version. 2961 s.startBlock(bFalse) 2962 a := s.call(n, callNormal) 2963 s.vars[n] = s.newValue2(ssa.OpLoad, types.Types[TINT], a, s.mem()) 2964 s.endBlock().AddEdgeTo(bEnd) 2965 2966 // Merge results. 2967 s.startBlock(bEnd) 2968 return s.variable(n, types.Types[TINT]) 2969 } 2970 } 2971 addF("math/bits", "OnesCount64", 2972 makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount64), 2973 sys.AMD64) 2974 addF("math/bits", "OnesCount64", 2975 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2976 return s.newValue1(ssa.OpPopCount64, types.Types[TINT], args[0]) 2977 }, 2978 sys.PPC64) 2979 addF("math/bits", "OnesCount32", 2980 makeOnesCountAMD64(ssa.OpPopCount32, ssa.OpPopCount32), 2981 sys.AMD64) 2982 addF("math/bits", "OnesCount32", 2983 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 2984 return s.newValue1(ssa.OpPopCount32, types.Types[TINT], args[0]) 2985 }, 2986 sys.PPC64) 2987 addF("math/bits", "OnesCount16", 2988 makeOnesCountAMD64(ssa.OpPopCount16, ssa.OpPopCount16), 2989 sys.AMD64) 2990 // Note: no OnesCount8, the Go implementation is faster - just a table load. 2991 addF("math/bits", "OnesCount", 2992 makeOnesCountAMD64(ssa.OpPopCount64, ssa.OpPopCount32), 2993 sys.AMD64) 2994 2995 /******** sync/atomic ********/ 2996 2997 // Note: these are disabled by flag_race in findIntrinsic below. 2998 alias("sync/atomic", "LoadInt32", "runtime/internal/atomic", "Load", all...) 2999 alias("sync/atomic", "LoadInt64", "runtime/internal/atomic", "Load64", all...) 3000 alias("sync/atomic", "LoadPointer", "runtime/internal/atomic", "Loadp", all...) 3001 alias("sync/atomic", "LoadUint32", "runtime/internal/atomic", "Load", all...) 3002 alias("sync/atomic", "LoadUint64", "runtime/internal/atomic", "Load64", all...) 3003 alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load", p4...) 3004 alias("sync/atomic", "LoadUintptr", "runtime/internal/atomic", "Load64", p8...) 3005 3006 alias("sync/atomic", "StoreInt32", "runtime/internal/atomic", "Store", all...) 3007 alias("sync/atomic", "StoreInt64", "runtime/internal/atomic", "Store64", all...) 3008 // Note: not StorePointer, that needs a write barrier. Same below for {CompareAnd}Swap. 3009 alias("sync/atomic", "StoreUint32", "runtime/internal/atomic", "Store", all...) 3010 alias("sync/atomic", "StoreUint64", "runtime/internal/atomic", "Store64", all...) 3011 alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store", p4...) 3012 alias("sync/atomic", "StoreUintptr", "runtime/internal/atomic", "Store64", p8...) 3013 3014 alias("sync/atomic", "SwapInt32", "runtime/internal/atomic", "Xchg", all...) 3015 alias("sync/atomic", "SwapInt64", "runtime/internal/atomic", "Xchg64", all...) 3016 alias("sync/atomic", "SwapUint32", "runtime/internal/atomic", "Xchg", all...) 3017 alias("sync/atomic", "SwapUint64", "runtime/internal/atomic", "Xchg64", all...) 3018 alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg", p4...) 3019 alias("sync/atomic", "SwapUintptr", "runtime/internal/atomic", "Xchg64", p8...) 3020 3021 alias("sync/atomic", "CompareAndSwapInt32", "runtime/internal/atomic", "Cas", all...) 3022 alias("sync/atomic", "CompareAndSwapInt64", "runtime/internal/atomic", "Cas64", all...) 3023 alias("sync/atomic", "CompareAndSwapUint32", "runtime/internal/atomic", "Cas", all...) 3024 alias("sync/atomic", "CompareAndSwapUint64", "runtime/internal/atomic", "Cas64", all...) 3025 alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas", p4...) 3026 alias("sync/atomic", "CompareAndSwapUintptr", "runtime/internal/atomic", "Cas64", p8...) 3027 3028 alias("sync/atomic", "AddInt32", "runtime/internal/atomic", "Xadd", all...) 3029 alias("sync/atomic", "AddInt64", "runtime/internal/atomic", "Xadd64", all...) 3030 alias("sync/atomic", "AddUint32", "runtime/internal/atomic", "Xadd", all...) 3031 alias("sync/atomic", "AddUint64", "runtime/internal/atomic", "Xadd64", all...) 3032 alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd", p4...) 3033 alias("sync/atomic", "AddUintptr", "runtime/internal/atomic", "Xadd64", p8...) 3034 3035 /******** math/big ********/ 3036 add("math/big", "mulWW", 3037 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 3038 return s.newValue2(ssa.OpMul64uhilo, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1]) 3039 }, 3040 sys.ArchAMD64) 3041 add("math/big", "divWW", 3042 func(s *state, n *Node, args []*ssa.Value) *ssa.Value { 3043 return s.newValue3(ssa.OpDiv128u, types.NewTuple(types.Types[TUINT64], types.Types[TUINT64]), args[0], args[1], args[2]) 3044 }, 3045 sys.ArchAMD64) 3046 } 3047 3048 // findIntrinsic returns a function which builds the SSA equivalent of the 3049 // function identified by the symbol sym. If sym is not an intrinsic call, returns nil. 3050 func findIntrinsic(sym *types.Sym) intrinsicBuilder { 3051 if ssa.IntrinsicsDisable { 3052 return nil 3053 } 3054 if sym == nil || sym.Pkg == nil { 3055 return nil 3056 } 3057 pkg := sym.Pkg.Path 3058 if sym.Pkg == localpkg { 3059 pkg = myimportpath 3060 } 3061 if flag_race && pkg == "sync/atomic" { 3062 // The race detector needs to be able to intercept these calls. 3063 // We can't intrinsify them. 3064 return nil 3065 } 3066 fn := sym.Name 3067 return intrinsics[intrinsicKey{thearch.LinkArch.Arch, pkg, fn}] 3068 } 3069 3070 func isIntrinsicCall(n *Node) bool { 3071 if n == nil || n.Left == nil { 3072 return false 3073 } 3074 return findIntrinsic(n.Left.Sym) != nil 3075 } 3076 3077 // intrinsicCall converts a call to a recognized intrinsic function into the intrinsic SSA operation. 3078 func (s *state) intrinsicCall(n *Node) *ssa.Value { 3079 v := findIntrinsic(n.Left.Sym)(s, n, s.intrinsicArgs(n)) 3080 if ssa.IntrinsicsDebug > 0 { 3081 x := v 3082 if x == nil { 3083 x = s.mem() 3084 } 3085 if x.Op == ssa.OpSelect0 || x.Op == ssa.OpSelect1 { 3086 x = x.Args[0] 3087 } 3088 Warnl(n.Pos, "intrinsic substitution for %v with %s", n.Left.Sym.Name, x.LongString()) 3089 } 3090 return v 3091 } 3092 3093 type callArg struct { 3094 offset int64 3095 v *ssa.Value 3096 } 3097 type byOffset []callArg 3098 3099 func (x byOffset) Len() int { return len(x) } 3100 func (x byOffset) Swap(i, j int) { x[i], x[j] = x[j], x[i] } 3101 func (x byOffset) Less(i, j int) bool { 3102 return x[i].offset < x[j].offset 3103 } 3104 3105 // intrinsicArgs extracts args from n, evaluates them to SSA values, and returns them. 3106 func (s *state) intrinsicArgs(n *Node) []*ssa.Value { 3107 // This code is complicated because of how walk transforms calls. For a call node, 3108 // each entry in n.List is either an assignment to OINDREGSP which actually 3109 // stores an arg, or an assignment to a temporary which computes an arg 3110 // which is later assigned. 3111 // The args can also be out of order. 3112 // TODO: when walk goes away someday, this code can go away also. 3113 var args []callArg 3114 temps := map[*Node]*ssa.Value{} 3115 for _, a := range n.List.Slice() { 3116 if a.Op != OAS { 3117 s.Fatalf("non-assignment as a function argument %s", opnames[a.Op]) 3118 } 3119 l, r := a.Left, a.Right 3120 switch l.Op { 3121 case ONAME: 3122 // Evaluate and store to "temporary". 3123 // Walk ensures these temporaries are dead outside of n. 3124 temps[l] = s.expr(r) 3125 case OINDREGSP: 3126 // Store a value to an argument slot. 3127 var v *ssa.Value 3128 if x, ok := temps[r]; ok { 3129 // This is a previously computed temporary. 3130 v = x 3131 } else { 3132 // This is an explicit value; evaluate it. 3133 v = s.expr(r) 3134 } 3135 args = append(args, callArg{l.Xoffset, v}) 3136 default: 3137 s.Fatalf("function argument assignment target not allowed: %s", opnames[l.Op]) 3138 } 3139 } 3140 sort.Sort(byOffset(args)) 3141 res := make([]*ssa.Value, len(args)) 3142 for i, a := range args { 3143 res[i] = a.v 3144 } 3145 return res 3146 } 3147 3148 // Calls the function n using the specified call type. 3149 // Returns the address of the return value (or nil if none). 3150 func (s *state) call(n *Node, k callKind) *ssa.Value { 3151 var sym *types.Sym // target symbol (if static) 3152 var closure *ssa.Value // ptr to closure to run (if dynamic) 3153 var codeptr *ssa.Value // ptr to target code (if dynamic) 3154 var rcvr *ssa.Value // receiver to set 3155 fn := n.Left 3156 switch n.Op { 3157 case OCALLFUNC: 3158 if k == callNormal && fn.Op == ONAME && fn.Class() == PFUNC { 3159 sym = fn.Sym 3160 break 3161 } 3162 closure = s.expr(fn) 3163 case OCALLMETH: 3164 if fn.Op != ODOTMETH { 3165 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn) 3166 } 3167 if k == callNormal { 3168 sym = fn.Sym 3169 break 3170 } 3171 // Make a name n2 for the function. 3172 // fn.Sym might be sync.(*Mutex).Unlock. 3173 // Make a PFUNC node out of that, then evaluate it. 3174 // We get back an SSA value representing &sync.(*Mutex).Unlock·f. 3175 // We can then pass that to defer or go. 3176 n2 := newnamel(fn.Pos, fn.Sym) 3177 n2.Name.Curfn = s.curfn 3178 n2.SetClass(PFUNC) 3179 n2.Pos = fn.Pos 3180 n2.Type = types.Types[TUINT8] // dummy type for a static closure. Could use runtime.funcval if we had it. 3181 closure = s.expr(n2) 3182 // Note: receiver is already assigned in n.List, so we don't 3183 // want to set it here. 3184 case OCALLINTER: 3185 if fn.Op != ODOTINTER { 3186 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op) 3187 } 3188 i := s.expr(fn.Left) 3189 itab := s.newValue1(ssa.OpITab, types.Types[TUINTPTR], i) 3190 if k != callNormal { 3191 s.nilCheck(itab) 3192 } 3193 itabidx := fn.Xoffset + 2*int64(Widthptr) + 8 // offset of fun field in runtime.itab 3194 itab = s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.UintptrPtr, itabidx, itab) 3195 if k == callNormal { 3196 codeptr = s.newValue2(ssa.OpLoad, types.Types[TUINTPTR], itab, s.mem()) 3197 } else { 3198 closure = itab 3199 } 3200 rcvr = s.newValue1(ssa.OpIData, types.Types[TUINTPTR], i) 3201 } 3202 dowidth(fn.Type) 3203 stksize := fn.Type.ArgWidth() // includes receiver 3204 3205 // Run all argument assignments. The arg slots have already 3206 // been offset by the appropriate amount (+2*widthptr for go/defer, 3207 // +widthptr for interface calls). 3208 // For OCALLMETH, the receiver is set in these statements. 3209 s.stmtList(n.List) 3210 3211 // Set receiver (for interface calls) 3212 if rcvr != nil { 3213 argStart := Ctxt.FixedFrameSize() 3214 if k != callNormal { 3215 argStart += int64(2 * Widthptr) 3216 } 3217 addr := s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart) 3218 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], addr, rcvr, s.mem()) 3219 } 3220 3221 // Defer/go args 3222 if k != callNormal { 3223 // Write argsize and closure (args to Newproc/Deferproc). 3224 argStart := Ctxt.FixedFrameSize() 3225 argsize := s.constInt32(types.Types[TUINT32], int32(stksize)) 3226 addr := s.constOffPtrSP(s.f.Config.Types.UInt32Ptr, argStart) 3227 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINT32], addr, argsize, s.mem()) 3228 addr = s.constOffPtrSP(s.f.Config.Types.UintptrPtr, argStart+int64(Widthptr)) 3229 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], addr, closure, s.mem()) 3230 stksize += 2 * int64(Widthptr) 3231 } 3232 3233 // call target 3234 var call *ssa.Value 3235 switch { 3236 case k == callDefer: 3237 call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Deferproc, s.mem()) 3238 case k == callGo: 3239 call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, Newproc, s.mem()) 3240 case closure != nil: 3241 codeptr = s.newValue2(ssa.OpLoad, types.Types[TUINTPTR], closure, s.mem()) 3242 call = s.newValue3(ssa.OpClosureCall, types.TypeMem, codeptr, closure, s.mem()) 3243 case codeptr != nil: 3244 call = s.newValue2(ssa.OpInterCall, types.TypeMem, codeptr, s.mem()) 3245 case sym != nil: 3246 call = s.newValue1A(ssa.OpStaticCall, types.TypeMem, sym.Linksym(), s.mem()) 3247 default: 3248 Fatalf("bad call type %v %v", n.Op, n) 3249 } 3250 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them 3251 s.vars[&memVar] = call 3252 3253 // Finish block for defers 3254 if k == callDefer { 3255 b := s.endBlock() 3256 b.Kind = ssa.BlockDefer 3257 b.SetControl(call) 3258 bNext := s.f.NewBlock(ssa.BlockPlain) 3259 b.AddEdgeTo(bNext) 3260 // Add recover edge to exit code. 3261 r := s.f.NewBlock(ssa.BlockPlain) 3262 s.startBlock(r) 3263 s.exit() 3264 b.AddEdgeTo(r) 3265 b.Likely = ssa.BranchLikely 3266 s.startBlock(bNext) 3267 } 3268 3269 res := n.Left.Type.Results() 3270 if res.NumFields() == 0 || k != callNormal { 3271 // call has no return value. Continue with the next statement. 3272 return nil 3273 } 3274 fp := res.Field(0) 3275 return s.constOffPtrSP(types.NewPtr(fp.Type), fp.Offset+Ctxt.FixedFrameSize()) 3276 } 3277 3278 // etypesign returns the signed-ness of e, for integer/pointer etypes. 3279 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer. 3280 func etypesign(e types.EType) int8 { 3281 switch e { 3282 case TINT8, TINT16, TINT32, TINT64, TINT: 3283 return -1 3284 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR: 3285 return +1 3286 } 3287 return 0 3288 } 3289 3290 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. 3291 // The value that the returned Value represents is guaranteed to be non-nil. 3292 // If bounded is true then this address does not require a nil check for its operand 3293 // even if that would otherwise be implied. 3294 func (s *state) addr(n *Node, bounded bool) *ssa.Value { 3295 t := types.NewPtr(n.Type) 3296 switch n.Op { 3297 case ONAME: 3298 switch n.Class() { 3299 case PEXTERN: 3300 // global variable 3301 v := s.entryNewValue1A(ssa.OpAddr, t, n.Sym.Linksym(), s.sb) 3302 // TODO: Make OpAddr use AuxInt as well as Aux. 3303 if n.Xoffset != 0 { 3304 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v) 3305 } 3306 return v 3307 case PPARAM: 3308 // parameter slot 3309 v := s.decladdrs[n] 3310 if v != nil { 3311 return v 3312 } 3313 if n == nodfp { 3314 // Special arg that points to the frame pointer (Used by ORECOVER). 3315 return s.entryNewValue1A(ssa.OpAddr, t, n, s.sp) 3316 } 3317 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) 3318 return nil 3319 case PAUTO: 3320 return s.newValue1A(ssa.OpAddr, t, n, s.sp) 3321 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early. 3322 // ensure that we reuse symbols for out parameters so 3323 // that cse works on their addresses 3324 return s.newValue1A(ssa.OpAddr, t, n, s.sp) 3325 default: 3326 s.Fatalf("variable address class %v not implemented", classnames[n.Class()]) 3327 return nil 3328 } 3329 case OINDREGSP: 3330 // indirect off REGSP 3331 // used for storing/loading arguments/returns to/from callees 3332 return s.constOffPtrSP(t, n.Xoffset) 3333 case OINDEX: 3334 if n.Left.Type.IsSlice() { 3335 a := s.expr(n.Left) 3336 i := s.expr(n.Right) 3337 i = s.extendIndex(i, panicindex) 3338 len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], a) 3339 if !n.Bounded() { 3340 s.boundsCheck(i, len) 3341 } 3342 p := s.newValue1(ssa.OpSlicePtr, t, a) 3343 return s.newValue2(ssa.OpPtrIndex, t, p, i) 3344 } else { // array 3345 a := s.addr(n.Left, bounded) 3346 i := s.expr(n.Right) 3347 i = s.extendIndex(i, panicindex) 3348 len := s.constInt(types.Types[TINT], n.Left.Type.NumElem()) 3349 if !n.Bounded() { 3350 s.boundsCheck(i, len) 3351 } 3352 return s.newValue2(ssa.OpPtrIndex, types.NewPtr(n.Left.Type.Elem()), a, i) 3353 } 3354 case OIND: 3355 return s.exprPtr(n.Left, bounded, n.Pos) 3356 case ODOT: 3357 p := s.addr(n.Left, bounded) 3358 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p) 3359 case ODOTPTR: 3360 p := s.exprPtr(n.Left, bounded, n.Pos) 3361 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p) 3362 case OCLOSUREVAR: 3363 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, 3364 s.entryNewValue0(ssa.OpGetClosurePtr, s.f.Config.Types.BytePtr)) 3365 case OCONVNOP: 3366 addr := s.addr(n.Left, bounded) 3367 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type 3368 case OCALLFUNC, OCALLINTER, OCALLMETH: 3369 return s.call(n, callNormal) 3370 case ODOTTYPE: 3371 v, _ := s.dottype(n, false) 3372 if v.Op != ssa.OpLoad { 3373 s.Fatalf("dottype of non-load") 3374 } 3375 if v.Args[1] != s.mem() { 3376 s.Fatalf("memory no longer live from dottype load") 3377 } 3378 return v.Args[0] 3379 default: 3380 s.Fatalf("unhandled addr %v", n.Op) 3381 return nil 3382 } 3383 } 3384 3385 // canSSA reports whether n is SSA-able. 3386 // n must be an ONAME (or an ODOT sequence with an ONAME base). 3387 func (s *state) canSSA(n *Node) bool { 3388 if Debug['N'] != 0 { 3389 return false 3390 } 3391 for n.Op == ODOT || (n.Op == OINDEX && n.Left.Type.IsArray()) { 3392 n = n.Left 3393 } 3394 if n.Op != ONAME { 3395 return false 3396 } 3397 if n.Addrtaken() { 3398 return false 3399 } 3400 if n.isParamHeapCopy() { 3401 return false 3402 } 3403 if n.Class() == PAUTOHEAP { 3404 Fatalf("canSSA of PAUTOHEAP %v", n) 3405 } 3406 switch n.Class() { 3407 case PEXTERN: 3408 return false 3409 case PPARAMOUT: 3410 if s.hasdefer { 3411 // TODO: handle this case? Named return values must be 3412 // in memory so that the deferred function can see them. 3413 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false } 3414 // Or maybe not, see issue 18860. Even unnamed return values 3415 // must be written back so if a defer recovers, the caller can see them. 3416 return false 3417 } 3418 if s.cgoUnsafeArgs { 3419 // Cgo effectively takes the address of all result args, 3420 // but the compiler can't see that. 3421 return false 3422 } 3423 } 3424 if n.Class() == PPARAM && n.Sym != nil && n.Sym.Name == ".this" { 3425 // wrappers generated by genwrapper need to update 3426 // the .this pointer in place. 3427 // TODO: treat as a PPARMOUT? 3428 return false 3429 } 3430 return canSSAType(n.Type) 3431 // TODO: try to make more variables SSAable? 3432 } 3433 3434 // canSSA reports whether variables of type t are SSA-able. 3435 func canSSAType(t *types.Type) bool { 3436 dowidth(t) 3437 if t.Width > int64(4*Widthptr) { 3438 // 4*Widthptr is an arbitrary constant. We want it 3439 // to be at least 3*Widthptr so slices can be registerized. 3440 // Too big and we'll introduce too much register pressure. 3441 return false 3442 } 3443 switch t.Etype { 3444 case TARRAY: 3445 // We can't do larger arrays because dynamic indexing is 3446 // not supported on SSA variables. 3447 // TODO: allow if all indexes are constant. 3448 if t.NumElem() <= 1 { 3449 return canSSAType(t.Elem()) 3450 } 3451 return false 3452 case TSTRUCT: 3453 if t.NumFields() > ssa.MaxStruct { 3454 return false 3455 } 3456 for _, t1 := range t.Fields().Slice() { 3457 if !canSSAType(t1.Type) { 3458 return false 3459 } 3460 } 3461 return true 3462 default: 3463 return true 3464 } 3465 } 3466 3467 // exprPtr evaluates n to a pointer and nil-checks it. 3468 func (s *state) exprPtr(n *Node, bounded bool, lineno src.XPos) *ssa.Value { 3469 p := s.expr(n) 3470 if bounded || n.NonNil() { 3471 if s.f.Frontend().Debug_checknil() && lineno.Line() > 1 { 3472 s.f.Warnl(lineno, "removed nil check") 3473 } 3474 return p 3475 } 3476 s.nilCheck(p) 3477 return p 3478 } 3479 3480 // nilCheck generates nil pointer checking code. 3481 // Used only for automatically inserted nil checks, 3482 // not for user code like 'x != nil'. 3483 func (s *state) nilCheck(ptr *ssa.Value) { 3484 if disable_checknil != 0 || s.curfn.Func.NilCheckDisabled() { 3485 return 3486 } 3487 s.newValue2(ssa.OpNilCheck, types.TypeVoid, ptr, s.mem()) 3488 } 3489 3490 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not. 3491 // Starts a new block on return. 3492 // idx is already converted to full int width. 3493 func (s *state) boundsCheck(idx, len *ssa.Value) { 3494 if Debug['B'] != 0 { 3495 return 3496 } 3497 3498 // bounds check 3499 cmp := s.newValue2(ssa.OpIsInBounds, types.Types[TBOOL], idx, len) 3500 s.check(cmp, panicindex) 3501 } 3502 3503 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not. 3504 // Starts a new block on return. 3505 // idx and len are already converted to full int width. 3506 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) { 3507 if Debug['B'] != 0 { 3508 return 3509 } 3510 3511 // bounds check 3512 cmp := s.newValue2(ssa.OpIsSliceInBounds, types.Types[TBOOL], idx, len) 3513 s.check(cmp, panicslice) 3514 } 3515 3516 // If cmp (a bool) is false, panic using the given function. 3517 func (s *state) check(cmp *ssa.Value, fn *obj.LSym) { 3518 b := s.endBlock() 3519 b.Kind = ssa.BlockIf 3520 b.SetControl(cmp) 3521 b.Likely = ssa.BranchLikely 3522 bNext := s.f.NewBlock(ssa.BlockPlain) 3523 line := s.peekPos() 3524 pos := Ctxt.PosTable.Pos(line) 3525 fl := funcLine{f: fn, base: pos.Base(), line: pos.Line()} 3526 bPanic := s.panics[fl] 3527 if bPanic == nil { 3528 bPanic = s.f.NewBlock(ssa.BlockPlain) 3529 s.panics[fl] = bPanic 3530 s.startBlock(bPanic) 3531 // The panic call takes/returns memory to ensure that the right 3532 // memory state is observed if the panic happens. 3533 s.rtcall(fn, false, nil) 3534 } 3535 b.AddEdgeTo(bNext) 3536 b.AddEdgeTo(bPanic) 3537 s.startBlock(bNext) 3538 } 3539 3540 func (s *state) intDivide(n *Node, a, b *ssa.Value) *ssa.Value { 3541 needcheck := true 3542 switch b.Op { 3543 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64: 3544 if b.AuxInt != 0 { 3545 needcheck = false 3546 } 3547 } 3548 if needcheck { 3549 // do a size-appropriate check for zero 3550 cmp := s.newValue2(s.ssaOp(ONE, n.Type), types.Types[TBOOL], b, s.zeroVal(n.Type)) 3551 s.check(cmp, panicdivide) 3552 } 3553 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b) 3554 } 3555 3556 // rtcall issues a call to the given runtime function fn with the listed args. 3557 // Returns a slice of results of the given result types. 3558 // The call is added to the end of the current block. 3559 // If returns is false, the block is marked as an exit block. 3560 func (s *state) rtcall(fn *obj.LSym, returns bool, results []*types.Type, args ...*ssa.Value) []*ssa.Value { 3561 // Write args to the stack 3562 off := Ctxt.FixedFrameSize() 3563 for _, arg := range args { 3564 t := arg.Type 3565 off = Rnd(off, t.Alignment()) 3566 ptr := s.constOffPtrSP(t.PtrTo(), off) 3567 size := t.Size() 3568 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, ptr, arg, s.mem()) 3569 off += size 3570 } 3571 off = Rnd(off, int64(Widthreg)) 3572 3573 // Issue call 3574 call := s.newValue1A(ssa.OpStaticCall, types.TypeMem, fn, s.mem()) 3575 s.vars[&memVar] = call 3576 3577 if !returns { 3578 // Finish block 3579 b := s.endBlock() 3580 b.Kind = ssa.BlockExit 3581 b.SetControl(call) 3582 call.AuxInt = off - Ctxt.FixedFrameSize() 3583 if len(results) > 0 { 3584 Fatalf("panic call can't have results") 3585 } 3586 return nil 3587 } 3588 3589 // Load results 3590 res := make([]*ssa.Value, len(results)) 3591 for i, t := range results { 3592 off = Rnd(off, t.Alignment()) 3593 ptr := s.constOffPtrSP(types.NewPtr(t), off) 3594 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem()) 3595 off += t.Size() 3596 } 3597 off = Rnd(off, int64(Widthptr)) 3598 3599 // Remember how much callee stack space we needed. 3600 call.AuxInt = off 3601 3602 return res 3603 } 3604 3605 // do *left = right for type t. 3606 func (s *state) storeType(t *types.Type, left, right *ssa.Value, skip skipMask) { 3607 if skip == 0 && (!types.Haspointers(t) || ssa.IsStackAddr(left)) { 3608 // Known to not have write barrier. Store the whole type. 3609 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, left, right, s.mem()) 3610 return 3611 } 3612 3613 // store scalar fields first, so write barrier stores for 3614 // pointer fields can be grouped together, and scalar values 3615 // don't need to be live across the write barrier call. 3616 // TODO: if the writebarrier pass knows how to reorder stores, 3617 // we can do a single store here as long as skip==0. 3618 s.storeTypeScalars(t, left, right, skip) 3619 if skip&skipPtr == 0 && types.Haspointers(t) { 3620 s.storeTypePtrs(t, left, right) 3621 } 3622 } 3623 3624 // do *left = right for all scalar (non-pointer) parts of t. 3625 func (s *state) storeTypeScalars(t *types.Type, left, right *ssa.Value, skip skipMask) { 3626 switch { 3627 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex(): 3628 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, left, right, s.mem()) 3629 case t.IsPtrShaped(): 3630 // no scalar fields. 3631 case t.IsString(): 3632 if skip&skipLen != 0 { 3633 return 3634 } 3635 len := s.newValue1(ssa.OpStringLen, types.Types[TINT], right) 3636 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left) 3637 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], lenAddr, len, s.mem()) 3638 case t.IsSlice(): 3639 if skip&skipLen == 0 { 3640 len := s.newValue1(ssa.OpSliceLen, types.Types[TINT], right) 3641 lenAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, s.config.PtrSize, left) 3642 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], lenAddr, len, s.mem()) 3643 } 3644 if skip&skipCap == 0 { 3645 cap := s.newValue1(ssa.OpSliceCap, types.Types[TINT], right) 3646 capAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.IntPtr, 2*s.config.PtrSize, left) 3647 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TINT], capAddr, cap, s.mem()) 3648 } 3649 case t.IsInterface(): 3650 // itab field doesn't need a write barrier (even though it is a pointer). 3651 itab := s.newValue1(ssa.OpITab, s.f.Config.Types.BytePtr, right) 3652 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, types.Types[TUINTPTR], left, itab, s.mem()) 3653 case t.IsStruct(): 3654 n := t.NumFields() 3655 for i := 0; i < n; i++ { 3656 ft := t.FieldType(i) 3657 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left) 3658 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right) 3659 s.storeTypeScalars(ft, addr, val, 0) 3660 } 3661 case t.IsArray() && t.NumElem() == 0: 3662 // nothing 3663 case t.IsArray() && t.NumElem() == 1: 3664 s.storeTypeScalars(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right), 0) 3665 default: 3666 s.Fatalf("bad write barrier type %v", t) 3667 } 3668 } 3669 3670 // do *left = right for all pointer parts of t. 3671 func (s *state) storeTypePtrs(t *types.Type, left, right *ssa.Value) { 3672 switch { 3673 case t.IsPtrShaped(): 3674 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, t, left, right, s.mem()) 3675 case t.IsString(): 3676 ptr := s.newValue1(ssa.OpStringPtr, s.f.Config.Types.BytePtr, right) 3677 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, left, ptr, s.mem()) 3678 case t.IsSlice(): 3679 ptr := s.newValue1(ssa.OpSlicePtr, s.f.Config.Types.BytePtr, right) 3680 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, left, ptr, s.mem()) 3681 case t.IsInterface(): 3682 // itab field is treated as a scalar. 3683 idata := s.newValue1(ssa.OpIData, s.f.Config.Types.BytePtr, right) 3684 idataAddr := s.newValue1I(ssa.OpOffPtr, s.f.Config.Types.BytePtrPtr, s.config.PtrSize, left) 3685 s.vars[&memVar] = s.newValue3A(ssa.OpStore, types.TypeMem, s.f.Config.Types.BytePtr, idataAddr, idata, s.mem()) 3686 case t.IsStruct(): 3687 n := t.NumFields() 3688 for i := 0; i < n; i++ { 3689 ft := t.FieldType(i) 3690 if !types.Haspointers(ft) { 3691 continue 3692 } 3693 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left) 3694 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right) 3695 s.storeTypePtrs(ft, addr, val) 3696 } 3697 case t.IsArray() && t.NumElem() == 0: 3698 // nothing 3699 case t.IsArray() && t.NumElem() == 1: 3700 s.storeTypePtrs(t.Elem(), left, s.newValue1I(ssa.OpArraySelect, t.Elem(), 0, right)) 3701 default: 3702 s.Fatalf("bad write barrier type %v", t) 3703 } 3704 } 3705 3706 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result. 3707 // i,j,k may be nil, in which case they are set to their default value. 3708 // t is a slice, ptr to array, or string type. 3709 func (s *state) slice(t *types.Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) { 3710 var elemtype *types.Type 3711 var ptrtype *types.Type 3712 var ptr *ssa.Value 3713 var len *ssa.Value 3714 var cap *ssa.Value 3715 zero := s.constInt(types.Types[TINT], 0) 3716 switch { 3717 case t.IsSlice(): 3718 elemtype = t.Elem() 3719 ptrtype = types.NewPtr(elemtype) 3720 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v) 3721 len = s.newValue1(ssa.OpSliceLen, types.Types[TINT], v) 3722 cap = s.newValue1(ssa.OpSliceCap, types.Types[TINT], v) 3723 case t.IsString(): 3724 elemtype = types.Types[TUINT8] 3725 ptrtype = types.NewPtr(elemtype) 3726 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v) 3727 len = s.newValue1(ssa.OpStringLen, types.Types[TINT], v) 3728 cap = len 3729 case t.IsPtr(): 3730 if !t.Elem().IsArray() { 3731 s.Fatalf("bad ptr to array in slice %v\n", t) 3732 } 3733 elemtype = t.Elem().Elem() 3734 ptrtype = types.NewPtr(elemtype) 3735 s.nilCheck(v) 3736 ptr = v 3737 len = s.constInt(types.Types[TINT], t.Elem().NumElem()) 3738 cap = len 3739 default: 3740 s.Fatalf("bad type in slice %v\n", t) 3741 } 3742 3743 // Set default values 3744 if i == nil { 3745 i = zero 3746 } 3747 if j == nil { 3748 j = len 3749 } 3750 if k == nil { 3751 k = cap 3752 } 3753 3754 // Panic if slice indices are not in bounds. 3755 s.sliceBoundsCheck(i, j) 3756 if j != k { 3757 s.sliceBoundsCheck(j, k) 3758 } 3759 if k != cap { 3760 s.sliceBoundsCheck(k, cap) 3761 } 3762 3763 // Generate the following code assuming that indexes are in bounds. 3764 // The masking is to make sure that we don't generate a slice 3765 // that points to the next object in memory. 3766 // rlen = j - i 3767 // rcap = k - i 3768 // delta = i * elemsize 3769 // rptr = p + delta&mask(rcap) 3770 // result = (SliceMake rptr rlen rcap) 3771 // where mask(x) is 0 if x==0 and -1 if x>0. 3772 subOp := s.ssaOp(OSUB, types.Types[TINT]) 3773 mulOp := s.ssaOp(OMUL, types.Types[TINT]) 3774 andOp := s.ssaOp(OAND, types.Types[TINT]) 3775 rlen := s.newValue2(subOp, types.Types[TINT], j, i) 3776 var rcap *ssa.Value 3777 switch { 3778 case t.IsString(): 3779 // Capacity of the result is unimportant. However, we use 3780 // rcap to test if we've generated a zero-length slice. 3781 // Use length of strings for that. 3782 rcap = rlen 3783 case j == k: 3784 rcap = rlen 3785 default: 3786 rcap = s.newValue2(subOp, types.Types[TINT], k, i) 3787 } 3788 3789 var rptr *ssa.Value 3790 if (i.Op == ssa.OpConst64 || i.Op == ssa.OpConst32) && i.AuxInt == 0 { 3791 // No pointer arithmetic necessary. 3792 rptr = ptr 3793 } else { 3794 // delta = # of bytes to offset pointer by. 3795 delta := s.newValue2(mulOp, types.Types[TINT], i, s.constInt(types.Types[TINT], elemtype.Width)) 3796 // If we're slicing to the point where the capacity is zero, 3797 // zero out the delta. 3798 mask := s.newValue1(ssa.OpSlicemask, types.Types[TINT], rcap) 3799 delta = s.newValue2(andOp, types.Types[TINT], delta, mask) 3800 // Compute rptr = ptr + delta 3801 rptr = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, delta) 3802 } 3803 3804 return rptr, rlen, rcap 3805 } 3806 3807 type u642fcvtTab struct { 3808 geq, cvt2F, and, rsh, or, add ssa.Op 3809 one func(*state, *types.Type, int64) *ssa.Value 3810 } 3811 3812 var u64_f64 = u642fcvtTab{ 3813 geq: ssa.OpGeq64, 3814 cvt2F: ssa.OpCvt64to64F, 3815 and: ssa.OpAnd64, 3816 rsh: ssa.OpRsh64Ux64, 3817 or: ssa.OpOr64, 3818 add: ssa.OpAdd64F, 3819 one: (*state).constInt64, 3820 } 3821 3822 var u64_f32 = u642fcvtTab{ 3823 geq: ssa.OpGeq64, 3824 cvt2F: ssa.OpCvt64to32F, 3825 and: ssa.OpAnd64, 3826 rsh: ssa.OpRsh64Ux64, 3827 or: ssa.OpOr64, 3828 add: ssa.OpAdd32F, 3829 one: (*state).constInt64, 3830 } 3831 3832 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3833 return s.uint64Tofloat(&u64_f64, n, x, ft, tt) 3834 } 3835 3836 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3837 return s.uint64Tofloat(&u64_f32, n, x, ft, tt) 3838 } 3839 3840 func (s *state) uint64Tofloat(cvttab *u642fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3841 // if x >= 0 { 3842 // result = (floatY) x 3843 // } else { 3844 // y = uintX(x) ; y = x & 1 3845 // z = uintX(x) ; z = z >> 1 3846 // z = z >> 1 3847 // z = z | y 3848 // result = floatY(z) 3849 // result = result + result 3850 // } 3851 // 3852 // Code borrowed from old code generator. 3853 // What's going on: large 64-bit "unsigned" looks like 3854 // negative number to hardware's integer-to-float 3855 // conversion. However, because the mantissa is only 3856 // 63 bits, we don't need the LSB, so instead we do an 3857 // unsigned right shift (divide by two), convert, and 3858 // double. However, before we do that, we need to be 3859 // sure that we do not lose a "1" if that made the 3860 // difference in the resulting rounding. Therefore, we 3861 // preserve it, and OR (not ADD) it back in. The case 3862 // that matters is when the eleven discarded bits are 3863 // equal to 10000000001; that rounds up, and the 1 cannot 3864 // be lost else it would round down if the LSB of the 3865 // candidate mantissa is 0. 3866 cmp := s.newValue2(cvttab.geq, types.Types[TBOOL], x, s.zeroVal(ft)) 3867 b := s.endBlock() 3868 b.Kind = ssa.BlockIf 3869 b.SetControl(cmp) 3870 b.Likely = ssa.BranchLikely 3871 3872 bThen := s.f.NewBlock(ssa.BlockPlain) 3873 bElse := s.f.NewBlock(ssa.BlockPlain) 3874 bAfter := s.f.NewBlock(ssa.BlockPlain) 3875 3876 b.AddEdgeTo(bThen) 3877 s.startBlock(bThen) 3878 a0 := s.newValue1(cvttab.cvt2F, tt, x) 3879 s.vars[n] = a0 3880 s.endBlock() 3881 bThen.AddEdgeTo(bAfter) 3882 3883 b.AddEdgeTo(bElse) 3884 s.startBlock(bElse) 3885 one := cvttab.one(s, ft, 1) 3886 y := s.newValue2(cvttab.and, ft, x, one) 3887 z := s.newValue2(cvttab.rsh, ft, x, one) 3888 z = s.newValue2(cvttab.or, ft, z, y) 3889 a := s.newValue1(cvttab.cvt2F, tt, z) 3890 a1 := s.newValue2(cvttab.add, tt, a, a) 3891 s.vars[n] = a1 3892 s.endBlock() 3893 bElse.AddEdgeTo(bAfter) 3894 3895 s.startBlock(bAfter) 3896 return s.variable(n, n.Type) 3897 } 3898 3899 type u322fcvtTab struct { 3900 cvtI2F, cvtF2F ssa.Op 3901 } 3902 3903 var u32_f64 = u322fcvtTab{ 3904 cvtI2F: ssa.OpCvt32to64F, 3905 cvtF2F: ssa.OpCopy, 3906 } 3907 3908 var u32_f32 = u322fcvtTab{ 3909 cvtI2F: ssa.OpCvt32to32F, 3910 cvtF2F: ssa.OpCvt64Fto32F, 3911 } 3912 3913 func (s *state) uint32Tofloat64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3914 return s.uint32Tofloat(&u32_f64, n, x, ft, tt) 3915 } 3916 3917 func (s *state) uint32Tofloat32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3918 return s.uint32Tofloat(&u32_f32, n, x, ft, tt) 3919 } 3920 3921 func (s *state) uint32Tofloat(cvttab *u322fcvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 3922 // if x >= 0 { 3923 // result = floatY(x) 3924 // } else { 3925 // result = floatY(float64(x) + (1<<32)) 3926 // } 3927 cmp := s.newValue2(ssa.OpGeq32, types.Types[TBOOL], x, s.zeroVal(ft)) 3928 b := s.endBlock() 3929 b.Kind = ssa.BlockIf 3930 b.SetControl(cmp) 3931 b.Likely = ssa.BranchLikely 3932 3933 bThen := s.f.NewBlock(ssa.BlockPlain) 3934 bElse := s.f.NewBlock(ssa.BlockPlain) 3935 bAfter := s.f.NewBlock(ssa.BlockPlain) 3936 3937 b.AddEdgeTo(bThen) 3938 s.startBlock(bThen) 3939 a0 := s.newValue1(cvttab.cvtI2F, tt, x) 3940 s.vars[n] = a0 3941 s.endBlock() 3942 bThen.AddEdgeTo(bAfter) 3943 3944 b.AddEdgeTo(bElse) 3945 s.startBlock(bElse) 3946 a1 := s.newValue1(ssa.OpCvt32to64F, types.Types[TFLOAT64], x) 3947 twoToThe32 := s.constFloat64(types.Types[TFLOAT64], float64(1<<32)) 3948 a2 := s.newValue2(ssa.OpAdd64F, types.Types[TFLOAT64], a1, twoToThe32) 3949 a3 := s.newValue1(cvttab.cvtF2F, tt, a2) 3950 3951 s.vars[n] = a3 3952 s.endBlock() 3953 bElse.AddEdgeTo(bAfter) 3954 3955 s.startBlock(bAfter) 3956 return s.variable(n, n.Type) 3957 } 3958 3959 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels. 3960 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value { 3961 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() { 3962 s.Fatalf("node must be a map or a channel") 3963 } 3964 // if n == nil { 3965 // return 0 3966 // } else { 3967 // // len 3968 // return *((*int)n) 3969 // // cap 3970 // return *(((*int)n)+1) 3971 // } 3972 lenType := n.Type 3973 nilValue := s.constNil(types.Types[TUINTPTR]) 3974 cmp := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], x, nilValue) 3975 b := s.endBlock() 3976 b.Kind = ssa.BlockIf 3977 b.SetControl(cmp) 3978 b.Likely = ssa.BranchUnlikely 3979 3980 bThen := s.f.NewBlock(ssa.BlockPlain) 3981 bElse := s.f.NewBlock(ssa.BlockPlain) 3982 bAfter := s.f.NewBlock(ssa.BlockPlain) 3983 3984 // length/capacity of a nil map/chan is zero 3985 b.AddEdgeTo(bThen) 3986 s.startBlock(bThen) 3987 s.vars[n] = s.zeroVal(lenType) 3988 s.endBlock() 3989 bThen.AddEdgeTo(bAfter) 3990 3991 b.AddEdgeTo(bElse) 3992 s.startBlock(bElse) 3993 if n.Op == OLEN { 3994 // length is stored in the first word for map/chan 3995 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem()) 3996 } else if n.Op == OCAP { 3997 // capacity is stored in the second word for chan 3998 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x) 3999 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem()) 4000 } else { 4001 s.Fatalf("op must be OLEN or OCAP") 4002 } 4003 s.endBlock() 4004 bElse.AddEdgeTo(bAfter) 4005 4006 s.startBlock(bAfter) 4007 return s.variable(n, lenType) 4008 } 4009 4010 type f2uCvtTab struct { 4011 ltf, cvt2U, subf, or ssa.Op 4012 floatValue func(*state, *types.Type, float64) *ssa.Value 4013 intValue func(*state, *types.Type, int64) *ssa.Value 4014 cutoff uint64 4015 } 4016 4017 var f32_u64 = f2uCvtTab{ 4018 ltf: ssa.OpLess32F, 4019 cvt2U: ssa.OpCvt32Fto64, 4020 subf: ssa.OpSub32F, 4021 or: ssa.OpOr64, 4022 floatValue: (*state).constFloat32, 4023 intValue: (*state).constInt64, 4024 cutoff: 9223372036854775808, 4025 } 4026 4027 var f64_u64 = f2uCvtTab{ 4028 ltf: ssa.OpLess64F, 4029 cvt2U: ssa.OpCvt64Fto64, 4030 subf: ssa.OpSub64F, 4031 or: ssa.OpOr64, 4032 floatValue: (*state).constFloat64, 4033 intValue: (*state).constInt64, 4034 cutoff: 9223372036854775808, 4035 } 4036 4037 var f32_u32 = f2uCvtTab{ 4038 ltf: ssa.OpLess32F, 4039 cvt2U: ssa.OpCvt32Fto32, 4040 subf: ssa.OpSub32F, 4041 or: ssa.OpOr32, 4042 floatValue: (*state).constFloat32, 4043 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) }, 4044 cutoff: 2147483648, 4045 } 4046 4047 var f64_u32 = f2uCvtTab{ 4048 ltf: ssa.OpLess64F, 4049 cvt2U: ssa.OpCvt64Fto32, 4050 subf: ssa.OpSub64F, 4051 or: ssa.OpOr32, 4052 floatValue: (*state).constFloat64, 4053 intValue: func(s *state, t *types.Type, v int64) *ssa.Value { return s.constInt32(t, int32(v)) }, 4054 cutoff: 2147483648, 4055 } 4056 4057 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 4058 return s.floatToUint(&f32_u64, n, x, ft, tt) 4059 } 4060 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 4061 return s.floatToUint(&f64_u64, n, x, ft, tt) 4062 } 4063 4064 func (s *state) float32ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 4065 return s.floatToUint(&f32_u32, n, x, ft, tt) 4066 } 4067 4068 func (s *state) float64ToUint32(n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 4069 return s.floatToUint(&f64_u32, n, x, ft, tt) 4070 } 4071 4072 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *types.Type) *ssa.Value { 4073 // cutoff:=1<<(intY_Size-1) 4074 // if x < floatX(cutoff) { 4075 // result = uintY(x) 4076 // } else { 4077 // y = x - floatX(cutoff) 4078 // z = uintY(y) 4079 // result = z | -(cutoff) 4080 // } 4081 cutoff := cvttab.floatValue(s, ft, float64(cvttab.cutoff)) 4082 cmp := s.newValue2(cvttab.ltf, types.Types[TBOOL], x, cutoff) 4083 b := s.endBlock() 4084 b.Kind = ssa.BlockIf 4085 b.SetControl(cmp) 4086 b.Likely = ssa.BranchLikely 4087 4088 bThen := s.f.NewBlock(ssa.BlockPlain) 4089 bElse := s.f.NewBlock(ssa.BlockPlain) 4090 bAfter := s.f.NewBlock(ssa.BlockPlain) 4091 4092 b.AddEdgeTo(bThen) 4093 s.startBlock(bThen) 4094 a0 := s.newValue1(cvttab.cvt2U, tt, x) 4095 s.vars[n] = a0 4096 s.endBlock() 4097 bThen.AddEdgeTo(bAfter) 4098 4099 b.AddEdgeTo(bElse) 4100 s.startBlock(bElse) 4101 y := s.newValue2(cvttab.subf, ft, x, cutoff) 4102 y = s.newValue1(cvttab.cvt2U, tt, y) 4103 z := cvttab.intValue(s, tt, int64(-cvttab.cutoff)) 4104 a1 := s.newValue2(cvttab.or, tt, y, z) 4105 s.vars[n] = a1 4106 s.endBlock() 4107 bElse.AddEdgeTo(bAfter) 4108 4109 s.startBlock(bAfter) 4110 return s.variable(n, n.Type) 4111 } 4112 4113 // dottype generates SSA for a type assertion node. 4114 // commaok indicates whether to panic or return a bool. 4115 // If commaok is false, resok will be nil. 4116 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) { 4117 iface := s.expr(n.Left) // input interface 4118 target := s.expr(n.Right) // target type 4119 byteptr := s.f.Config.Types.BytePtr 4120 4121 if n.Type.IsInterface() { 4122 if n.Type.IsEmptyInterface() { 4123 // Converting to an empty interface. 4124 // Input could be an empty or nonempty interface. 4125 if Debug_typeassert > 0 { 4126 Warnl(n.Pos, "type assertion inlined") 4127 } 4128 4129 // Get itab/type field from input. 4130 itab := s.newValue1(ssa.OpITab, byteptr, iface) 4131 // Conversion succeeds iff that field is not nil. 4132 cond := s.newValue2(ssa.OpNeqPtr, types.Types[TBOOL], itab, s.constNil(byteptr)) 4133 4134 if n.Left.Type.IsEmptyInterface() && commaok { 4135 // Converting empty interface to empty interface with ,ok is just a nil check. 4136 return iface, cond 4137 } 4138 4139 // Branch on nilness. 4140 b := s.endBlock() 4141 b.Kind = ssa.BlockIf 4142 b.SetControl(cond) 4143 b.Likely = ssa.BranchLikely 4144 bOk := s.f.NewBlock(ssa.BlockPlain) 4145 bFail := s.f.NewBlock(ssa.BlockPlain) 4146 b.AddEdgeTo(bOk) 4147 b.AddEdgeTo(bFail) 4148 4149 if !commaok { 4150 // On failure, panic by calling panicnildottype. 4151 s.startBlock(bFail) 4152 s.rtcall(panicnildottype, false, nil, target) 4153 4154 // On success, return (perhaps modified) input interface. 4155 s.startBlock(bOk) 4156 if n.Left.Type.IsEmptyInterface() { 4157 res = iface // Use input interface unchanged. 4158 return 4159 } 4160 // Load type out of itab, build interface with existing idata. 4161 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab) 4162 typ := s.newValue2(ssa.OpLoad, byteptr, off, s.mem()) 4163 idata := s.newValue1(ssa.OpIData, n.Type, iface) 4164 res = s.newValue2(ssa.OpIMake, n.Type, typ, idata) 4165 return 4166 } 4167 4168 s.startBlock(bOk) 4169 // nonempty -> empty 4170 // Need to load type from itab 4171 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), itab) 4172 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem()) 4173 s.endBlock() 4174 4175 // itab is nil, might as well use that as the nil result. 4176 s.startBlock(bFail) 4177 s.vars[&typVar] = itab 4178 s.endBlock() 4179 4180 // Merge point. 4181 bEnd := s.f.NewBlock(ssa.BlockPlain) 4182 bOk.AddEdgeTo(bEnd) 4183 bFail.AddEdgeTo(bEnd) 4184 s.startBlock(bEnd) 4185 idata := s.newValue1(ssa.OpIData, n.Type, iface) 4186 res = s.newValue2(ssa.OpIMake, n.Type, s.variable(&typVar, byteptr), idata) 4187 resok = cond 4188 delete(s.vars, &typVar) 4189 return 4190 } 4191 // converting to a nonempty interface needs a runtime call. 4192 if Debug_typeassert > 0 { 4193 Warnl(n.Pos, "type assertion not inlined") 4194 } 4195 if n.Left.Type.IsEmptyInterface() { 4196 if commaok { 4197 call := s.rtcall(assertE2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface) 4198 return call[0], call[1] 4199 } 4200 return s.rtcall(assertE2I, true, []*types.Type{n.Type}, target, iface)[0], nil 4201 } 4202 if commaok { 4203 call := s.rtcall(assertI2I2, true, []*types.Type{n.Type, types.Types[TBOOL]}, target, iface) 4204 return call[0], call[1] 4205 } 4206 return s.rtcall(assertI2I, true, []*types.Type{n.Type}, target, iface)[0], nil 4207 } 4208 4209 if Debug_typeassert > 0 { 4210 Warnl(n.Pos, "type assertion inlined") 4211 } 4212 4213 // Converting to a concrete type. 4214 direct := isdirectiface(n.Type) 4215 itab := s.newValue1(ssa.OpITab, byteptr, iface) // type word of interface 4216 if Debug_typeassert > 0 { 4217 Warnl(n.Pos, "type assertion inlined") 4218 } 4219 var targetITab *ssa.Value 4220 if n.Left.Type.IsEmptyInterface() { 4221 // Looking for pointer to target type. 4222 targetITab = target 4223 } else { 4224 // Looking for pointer to itab for target type and source interface. 4225 targetITab = s.expr(n.List.First()) 4226 } 4227 4228 var tmp *Node // temporary for use with large types 4229 var addr *ssa.Value // address of tmp 4230 if commaok && !canSSAType(n.Type) { 4231 // unSSAable type, use temporary. 4232 // TODO: get rid of some of these temporaries. 4233 tmp = tempAt(n.Pos, s.curfn, n.Type) 4234 addr = s.addr(tmp, false) 4235 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp, s.mem()) 4236 } 4237 4238 cond := s.newValue2(ssa.OpEqPtr, types.Types[TBOOL], itab, targetITab) 4239 b := s.endBlock() 4240 b.Kind = ssa.BlockIf 4241 b.SetControl(cond) 4242 b.Likely = ssa.BranchLikely 4243 4244 bOk := s.f.NewBlock(ssa.BlockPlain) 4245 bFail := s.f.NewBlock(ssa.BlockPlain) 4246 b.AddEdgeTo(bOk) 4247 b.AddEdgeTo(bFail) 4248 4249 if !commaok { 4250 // on failure, panic by calling panicdottype 4251 s.startBlock(bFail) 4252 taddr := s.expr(n.Right.Right) 4253 if n.Left.Type.IsEmptyInterface() { 4254 s.rtcall(panicdottypeE, false, nil, itab, target, taddr) 4255 } else { 4256 s.rtcall(panicdottypeI, false, nil, itab, target, taddr) 4257 } 4258 4259 // on success, return data from interface 4260 s.startBlock(bOk) 4261 if direct { 4262 return s.newValue1(ssa.OpIData, n.Type, iface), nil 4263 } 4264 p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface) 4265 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()), nil 4266 } 4267 4268 // commaok is the more complicated case because we have 4269 // a control flow merge point. 4270 bEnd := s.f.NewBlock(ssa.BlockPlain) 4271 // Note that we need a new valVar each time (unlike okVar where we can 4272 // reuse the variable) because it might have a different type every time. 4273 valVar := &Node{Op: ONAME, Sym: &types.Sym{Name: "val"}} 4274 4275 // type assertion succeeded 4276 s.startBlock(bOk) 4277 if tmp == nil { 4278 if direct { 4279 s.vars[valVar] = s.newValue1(ssa.OpIData, n.Type, iface) 4280 } else { 4281 p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface) 4282 s.vars[valVar] = s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) 4283 } 4284 } else { 4285 p := s.newValue1(ssa.OpIData, types.NewPtr(n.Type), iface) 4286 store := s.newValue3I(ssa.OpMove, types.TypeMem, n.Type.Size(), addr, p, s.mem()) 4287 store.Aux = n.Type 4288 s.vars[&memVar] = store 4289 } 4290 s.vars[&okVar] = s.constBool(true) 4291 s.endBlock() 4292 bOk.AddEdgeTo(bEnd) 4293 4294 // type assertion failed 4295 s.startBlock(bFail) 4296 if tmp == nil { 4297 s.vars[valVar] = s.zeroVal(n.Type) 4298 } else { 4299 store := s.newValue2I(ssa.OpZero, types.TypeMem, n.Type.Size(), addr, s.mem()) 4300 store.Aux = n.Type 4301 s.vars[&memVar] = store 4302 } 4303 s.vars[&okVar] = s.constBool(false) 4304 s.endBlock() 4305 bFail.AddEdgeTo(bEnd) 4306 4307 // merge point 4308 s.startBlock(bEnd) 4309 if tmp == nil { 4310 res = s.variable(valVar, n.Type) 4311 delete(s.vars, valVar) 4312 } else { 4313 res = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) 4314 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, types.TypeMem, tmp, s.mem()) 4315 } 4316 resok = s.variable(&okVar, types.Types[TBOOL]) 4317 delete(s.vars, &okVar) 4318 return res, resok 4319 } 4320 4321 // variable returns the value of a variable at the current location. 4322 func (s *state) variable(name *Node, t *types.Type) *ssa.Value { 4323 v := s.vars[name] 4324 if v != nil { 4325 return v 4326 } 4327 v = s.fwdVars[name] 4328 if v != nil { 4329 return v 4330 } 4331 4332 if s.curBlock == s.f.Entry { 4333 // No variable should be live at entry. 4334 s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, name, v) 4335 } 4336 // Make a FwdRef, which records a value that's live on block input. 4337 // We'll find the matching definition as part of insertPhis. 4338 v = s.newValue0A(ssa.OpFwdRef, t, name) 4339 s.fwdVars[name] = v 4340 s.addNamedValue(name, v) 4341 return v 4342 } 4343 4344 func (s *state) mem() *ssa.Value { 4345 return s.variable(&memVar, types.TypeMem) 4346 } 4347 4348 func (s *state) addNamedValue(n *Node, v *ssa.Value) { 4349 if n.Class() == Pxxx { 4350 // Don't track our dummy nodes (&memVar etc.). 4351 return 4352 } 4353 if n.IsAutoTmp() { 4354 // Don't track temporary variables. 4355 return 4356 } 4357 if n.Class() == PPARAMOUT { 4358 // Don't track named output values. This prevents return values 4359 // from being assigned too early. See #14591 and #14762. TODO: allow this. 4360 return 4361 } 4362 if n.Class() == PAUTO && n.Xoffset != 0 { 4363 s.Fatalf("AUTO var with offset %v %d", n, n.Xoffset) 4364 } 4365 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0} 4366 values, ok := s.f.NamedValues[loc] 4367 if !ok { 4368 s.f.Names = append(s.f.Names, loc) 4369 } 4370 s.f.NamedValues[loc] = append(values, v) 4371 } 4372 4373 // Branch is an unresolved branch. 4374 type Branch struct { 4375 P *obj.Prog // branch instruction 4376 B *ssa.Block // target 4377 } 4378 4379 // SSAGenState contains state needed during Prog generation. 4380 type SSAGenState struct { 4381 pp *Progs 4382 4383 // Branches remembers all the branch instructions we've seen 4384 // and where they would like to go. 4385 Branches []Branch 4386 4387 // bstart remembers where each block starts (indexed by block ID) 4388 bstart []*obj.Prog 4389 4390 // 387 port: maps from SSE registers (REG_X?) to 387 registers (REG_F?) 4391 SSEto387 map[int16]int16 4392 // Some architectures require a 64-bit temporary for FP-related register shuffling. Examples include x86-387, PPC, and Sparc V8. 4393 ScratchFpMem *Node 4394 4395 maxarg int64 // largest frame size for arguments to calls made by the function 4396 4397 // Map from GC safe points to stack map index, generated by 4398 // liveness analysis. 4399 stackMapIndex map[*ssa.Value]int 4400 } 4401 4402 // Prog appends a new Prog. 4403 func (s *SSAGenState) Prog(as obj.As) *obj.Prog { 4404 return s.pp.Prog(as) 4405 } 4406 4407 // Pc returns the current Prog. 4408 func (s *SSAGenState) Pc() *obj.Prog { 4409 return s.pp.next 4410 } 4411 4412 // SetPos sets the current source position. 4413 func (s *SSAGenState) SetPos(pos src.XPos) { 4414 s.pp.pos = pos 4415 } 4416 4417 // DebugFriendlySetPos sets the position subject to heuristics 4418 // that reduce "jumpy" line number churn when debugging. 4419 // Spill/fill/copy instructions from the register allocator, 4420 // phi functions, and instructions with a no-pos position 4421 // are examples of instructions that can cause churn. 4422 func (s *SSAGenState) DebugFriendlySetPosFrom(v *ssa.Value) { 4423 // The two choices here are either to leave lineno unchanged, 4424 // or to explicitly set it to src.NoXPos. Leaving it unchanged 4425 // (reusing the preceding line number) produces slightly better- 4426 // looking assembly language output from the compiler, and is 4427 // expected by some already-existing tests. 4428 // The debug information appears to be the same in either case 4429 switch v.Op { 4430 case ssa.OpPhi, ssa.OpCopy, ssa.OpLoadReg, ssa.OpStoreReg: 4431 // leave the position unchanged from beginning of block 4432 // or previous line number. 4433 default: 4434 if v.Pos != src.NoXPos { 4435 s.SetPos(v.Pos) 4436 } 4437 } 4438 } 4439 4440 // genssa appends entries to pp for each instruction in f. 4441 func genssa(f *ssa.Func, pp *Progs) { 4442 var s SSAGenState 4443 4444 e := f.Frontend().(*ssafn) 4445 4446 // Generate GC bitmaps, except if the stack is too large, 4447 // in which compilation will fail later anyway (issue 20529). 4448 if e.stksize < maxStackSize { 4449 s.stackMapIndex = liveness(e, f) 4450 } 4451 4452 // Remember where each block starts. 4453 s.bstart = make([]*obj.Prog, f.NumBlocks()) 4454 s.pp = pp 4455 var progToValue map[*obj.Prog]*ssa.Value 4456 var progToBlock map[*obj.Prog]*ssa.Block 4457 var valueToProg []*obj.Prog 4458 var logProgs = e.log 4459 if logProgs { 4460 progToValue = make(map[*obj.Prog]*ssa.Value, f.NumValues()) 4461 progToBlock = make(map[*obj.Prog]*ssa.Block, f.NumBlocks()) 4462 f.Logf("genssa %s\n", f.Name) 4463 progToBlock[s.pp.next] = f.Blocks[0] 4464 } 4465 4466 if thearch.Use387 { 4467 s.SSEto387 = map[int16]int16{} 4468 } 4469 4470 s.ScratchFpMem = e.scratchFpMem 4471 4472 logLocationLists := Debug_locationlist != 0 4473 if Ctxt.Flag_locationlists { 4474 e.curfn.Func.DebugInfo = ssa.BuildFuncDebug(f, logLocationLists) 4475 valueToProg = make([]*obj.Prog, f.NumValues()) 4476 } 4477 // Emit basic blocks 4478 for i, b := range f.Blocks { 4479 s.bstart[b.ID] = s.pp.next 4480 // Emit values in block 4481 thearch.SSAMarkMoves(&s, b) 4482 for _, v := range b.Values { 4483 x := s.pp.next 4484 s.DebugFriendlySetPosFrom(v) 4485 switch v.Op { 4486 case ssa.OpInitMem: 4487 // memory arg needs no code 4488 case ssa.OpArg: 4489 // input args need no code 4490 case ssa.OpSP, ssa.OpSB: 4491 // nothing to do 4492 case ssa.OpSelect0, ssa.OpSelect1: 4493 // nothing to do 4494 case ssa.OpGetG: 4495 // nothing to do when there's a g register, 4496 // and checkLower complains if there's not 4497 case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive: 4498 // nothing to do; already used by liveness 4499 case ssa.OpVarKill: 4500 // Zero variable if it is ambiguously live. 4501 // After the VARKILL anything this variable references 4502 // might be collected. If it were to become live again later, 4503 // the GC will see references to already-collected objects. 4504 // See issue 20029. 4505 n := v.Aux.(*Node) 4506 if n.Name.Needzero() { 4507 if n.Class() != PAUTO { 4508 v.Fatalf("zero of variable which isn't PAUTO %v", n) 4509 } 4510 if n.Type.Size()%int64(Widthptr) != 0 { 4511 v.Fatalf("zero of variable not a multiple of ptr size %v", n) 4512 } 4513 thearch.ZeroAuto(s.pp, n) 4514 } 4515 case ssa.OpPhi: 4516 CheckLoweredPhi(v) 4517 case ssa.OpRegKill: 4518 // nothing to do 4519 default: 4520 // let the backend handle it 4521 thearch.SSAGenValue(&s, v) 4522 } 4523 4524 if Ctxt.Flag_locationlists { 4525 valueToProg[v.ID] = x 4526 } 4527 if logProgs { 4528 for ; x != s.pp.next; x = x.Link { 4529 progToValue[x] = v 4530 } 4531 } 4532 } 4533 // Emit control flow instructions for block 4534 var next *ssa.Block 4535 if i < len(f.Blocks)-1 && Debug['N'] == 0 { 4536 // If -N, leave next==nil so every block with successors 4537 // ends in a JMP (except call blocks - plive doesn't like 4538 // select{send,recv} followed by a JMP call). Helps keep 4539 // line numbers for otherwise empty blocks. 4540 next = f.Blocks[i+1] 4541 } 4542 x := s.pp.next 4543 s.SetPos(b.Pos) 4544 thearch.SSAGenBlock(&s, b, next) 4545 if logProgs { 4546 for ; x != s.pp.next; x = x.Link { 4547 progToBlock[x] = b 4548 } 4549 } 4550 } 4551 4552 if Ctxt.Flag_locationlists { 4553 for i := range f.Blocks { 4554 blockDebug := e.curfn.Func.DebugInfo.Blocks[i] 4555 for _, locList := range blockDebug.Variables { 4556 for _, loc := range locList.Locations { 4557 if loc.Start == ssa.BlockStart { 4558 loc.StartProg = s.bstart[f.Blocks[i].ID] 4559 } else { 4560 loc.StartProg = valueToProg[loc.Start.ID] 4561 } 4562 if loc.End == nil { 4563 Fatalf("empty loc %v compiling %v", loc, f.Name) 4564 } 4565 4566 if loc.End == ssa.BlockEnd { 4567 // If this variable was live at the end of the block, it should be 4568 // live over the control flow instructions. Extend it up to the 4569 // beginning of the next block. 4570 // If this is the last block, then there's no Prog to use for it, and 4571 // EndProg is unset. 4572 if i < len(f.Blocks)-1 { 4573 loc.EndProg = s.bstart[f.Blocks[i+1].ID] 4574 } 4575 } else { 4576 loc.EndProg = valueToProg[loc.End.ID] 4577 } 4578 if !logLocationLists { 4579 loc.Start = nil 4580 loc.End = nil 4581 } 4582 } 4583 } 4584 } 4585 } 4586 4587 // Resolve branches 4588 for _, br := range s.Branches { 4589 br.P.To.Val = s.bstart[br.B.ID] 4590 } 4591 4592 if logProgs { 4593 for p := pp.Text; p != nil; p = p.Link { 4594 var s string 4595 if v, ok := progToValue[p]; ok { 4596 s = v.String() 4597 } else if b, ok := progToBlock[p]; ok { 4598 s = b.String() 4599 } else { 4600 s = " " // most value and branch strings are 2-3 characters long 4601 } 4602 f.Logf("%s\t%s\n", s, p) 4603 } 4604 if f.HTMLWriter != nil { 4605 // LineHist is defunct now - this code won't do 4606 // anything. 4607 // TODO: fix this (ideally without a global variable) 4608 // saved := pp.Text.Ctxt.LineHist.PrintFilenameOnly 4609 // pp.Text.Ctxt.LineHist.PrintFilenameOnly = true 4610 var buf bytes.Buffer 4611 buf.WriteString("<code>") 4612 buf.WriteString("<dl class=\"ssa-gen\">") 4613 for p := pp.Text; p != nil; p = p.Link { 4614 buf.WriteString("<dt class=\"ssa-prog-src\">") 4615 if v, ok := progToValue[p]; ok { 4616 buf.WriteString(v.HTML()) 4617 } else if b, ok := progToBlock[p]; ok { 4618 buf.WriteString(b.HTML()) 4619 } 4620 buf.WriteString("</dt>") 4621 buf.WriteString("<dd class=\"ssa-prog\">") 4622 buf.WriteString(html.EscapeString(p.String())) 4623 buf.WriteString("</dd>") 4624 buf.WriteString("</li>") 4625 } 4626 buf.WriteString("</dl>") 4627 buf.WriteString("</code>") 4628 f.HTMLWriter.WriteColumn("genssa", buf.String()) 4629 // pp.Text.Ctxt.LineHist.PrintFilenameOnly = saved 4630 } 4631 } 4632 4633 defframe(&s, e) 4634 if Debug['f'] != 0 { 4635 frame(0) 4636 } 4637 4638 f.HTMLWriter.Close() 4639 f.HTMLWriter = nil 4640 } 4641 4642 func defframe(s *SSAGenState, e *ssafn) { 4643 pp := s.pp 4644 4645 frame := Rnd(s.maxarg+e.stksize, int64(Widthreg)) 4646 if thearch.PadFrame != nil { 4647 frame = thearch.PadFrame(frame) 4648 } 4649 4650 // Fill in argument and frame size. 4651 pp.Text.To.Type = obj.TYPE_TEXTSIZE 4652 pp.Text.To.Val = int32(Rnd(e.curfn.Type.ArgWidth(), int64(Widthreg))) 4653 pp.Text.To.Offset = frame 4654 4655 // Insert code to zero ambiguously live variables so that the 4656 // garbage collector only sees initialized values when it 4657 // looks for pointers. 4658 p := pp.Text 4659 var lo, hi int64 4660 4661 // Opaque state for backend to use. Current backends use it to 4662 // keep track of which helper registers have been zeroed. 4663 var state uint32 4664 4665 // Iterate through declarations. They are sorted in decreasing Xoffset order. 4666 for _, n := range e.curfn.Func.Dcl { 4667 if !n.Name.Needzero() { 4668 continue 4669 } 4670 if n.Class() != PAUTO { 4671 Fatalf("needzero class %d", n.Class()) 4672 } 4673 if n.Type.Size()%int64(Widthptr) != 0 || n.Xoffset%int64(Widthptr) != 0 || n.Type.Size() == 0 { 4674 Fatalf("var %L has size %d offset %d", n, n.Type.Size(), n.Xoffset) 4675 } 4676 4677 if lo != hi && n.Xoffset+n.Type.Size() >= lo-int64(2*Widthreg) { 4678 // Merge with range we already have. 4679 lo = n.Xoffset 4680 continue 4681 } 4682 4683 // Zero old range 4684 p = thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state) 4685 4686 // Set new range. 4687 lo = n.Xoffset 4688 hi = lo + n.Type.Size() 4689 } 4690 4691 // Zero final range. 4692 thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state) 4693 } 4694 4695 type FloatingEQNEJump struct { 4696 Jump obj.As 4697 Index int 4698 } 4699 4700 func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) { 4701 p := s.Prog(jumps.Jump) 4702 p.To.Type = obj.TYPE_BRANCH 4703 p.Pos = b.Pos 4704 to := jumps.Index 4705 s.Branches = append(s.Branches, Branch{p, b.Succs[to].Block()}) 4706 } 4707 4708 func (s *SSAGenState) FPJump(b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) { 4709 switch next { 4710 case b.Succs[0].Block(): 4711 s.oneFPJump(b, &jumps[0][0]) 4712 s.oneFPJump(b, &jumps[0][1]) 4713 case b.Succs[1].Block(): 4714 s.oneFPJump(b, &jumps[1][0]) 4715 s.oneFPJump(b, &jumps[1][1]) 4716 default: 4717 s.oneFPJump(b, &jumps[1][0]) 4718 s.oneFPJump(b, &jumps[1][1]) 4719 q := s.Prog(obj.AJMP) 4720 q.Pos = b.Pos 4721 q.To.Type = obj.TYPE_BRANCH 4722 s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()}) 4723 } 4724 } 4725 4726 func AuxOffset(v *ssa.Value) (offset int64) { 4727 if v.Aux == nil { 4728 return 0 4729 } 4730 n, ok := v.Aux.(*Node) 4731 if !ok { 4732 v.Fatalf("bad aux type in %s\n", v.LongString()) 4733 } 4734 if n.Class() == PAUTO { 4735 return n.Xoffset 4736 } 4737 return 0 4738 } 4739 4740 // AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a. 4741 func AddAux(a *obj.Addr, v *ssa.Value) { 4742 AddAux2(a, v, v.AuxInt) 4743 } 4744 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) { 4745 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR { 4746 v.Fatalf("bad AddAux addr %v", a) 4747 } 4748 // add integer offset 4749 a.Offset += offset 4750 4751 // If no additional symbol offset, we're done. 4752 if v.Aux == nil { 4753 return 4754 } 4755 // Add symbol's offset from its base register. 4756 switch n := v.Aux.(type) { 4757 case *obj.LSym: 4758 a.Name = obj.NAME_EXTERN 4759 a.Sym = n 4760 case *Node: 4761 if n.Class() == PPARAM || n.Class() == PPARAMOUT { 4762 a.Name = obj.NAME_PARAM 4763 a.Sym = n.Orig.Sym.Linksym() 4764 a.Offset += n.Xoffset 4765 break 4766 } 4767 a.Name = obj.NAME_AUTO 4768 a.Sym = n.Sym.Linksym() 4769 a.Offset += n.Xoffset 4770 default: 4771 v.Fatalf("aux in %s not implemented %#v", v, v.Aux) 4772 } 4773 } 4774 4775 // extendIndex extends v to a full int width. 4776 // panic using the given function if v does not fit in an int (only on 32-bit archs). 4777 func (s *state) extendIndex(v *ssa.Value, panicfn *obj.LSym) *ssa.Value { 4778 size := v.Type.Size() 4779 if size == s.config.PtrSize { 4780 return v 4781 } 4782 if size > s.config.PtrSize { 4783 // truncate 64-bit indexes on 32-bit pointer archs. Test the 4784 // high word and branch to out-of-bounds failure if it is not 0. 4785 if Debug['B'] == 0 { 4786 hi := s.newValue1(ssa.OpInt64Hi, types.Types[TUINT32], v) 4787 cmp := s.newValue2(ssa.OpEq32, types.Types[TBOOL], hi, s.constInt32(types.Types[TUINT32], 0)) 4788 s.check(cmp, panicfn) 4789 } 4790 return s.newValue1(ssa.OpTrunc64to32, types.Types[TINT], v) 4791 } 4792 4793 // Extend value to the required size 4794 var op ssa.Op 4795 if v.Type.IsSigned() { 4796 switch 10*size + s.config.PtrSize { 4797 case 14: 4798 op = ssa.OpSignExt8to32 4799 case 18: 4800 op = ssa.OpSignExt8to64 4801 case 24: 4802 op = ssa.OpSignExt16to32 4803 case 28: 4804 op = ssa.OpSignExt16to64 4805 case 48: 4806 op = ssa.OpSignExt32to64 4807 default: 4808 s.Fatalf("bad signed index extension %s", v.Type) 4809 } 4810 } else { 4811 switch 10*size + s.config.PtrSize { 4812 case 14: 4813 op = ssa.OpZeroExt8to32 4814 case 18: 4815 op = ssa.OpZeroExt8to64 4816 case 24: 4817 op = ssa.OpZeroExt16to32 4818 case 28: 4819 op = ssa.OpZeroExt16to64 4820 case 48: 4821 op = ssa.OpZeroExt32to64 4822 default: 4823 s.Fatalf("bad unsigned index extension %s", v.Type) 4824 } 4825 } 4826 return s.newValue1(op, types.Types[TINT], v) 4827 } 4828 4829 // CheckLoweredPhi checks that regalloc and stackalloc correctly handled phi values. 4830 // Called during ssaGenValue. 4831 func CheckLoweredPhi(v *ssa.Value) { 4832 if v.Op != ssa.OpPhi { 4833 v.Fatalf("CheckLoweredPhi called with non-phi value: %v", v.LongString()) 4834 } 4835 if v.Type.IsMemory() { 4836 return 4837 } 4838 f := v.Block.Func 4839 loc := f.RegAlloc[v.ID] 4840 for _, a := range v.Args { 4841 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead? 4842 v.Fatalf("phi arg at different location than phi: %v @ %s, but arg %v @ %s\n%s\n", v, loc, a, aloc, v.Block.Func) 4843 } 4844 } 4845 } 4846 4847 // CheckLoweredGetClosurePtr checks that v is the first instruction in the function's entry block. 4848 // The output of LoweredGetClosurePtr is generally hardwired to the correct register. 4849 // That register contains the closure pointer on closure entry. 4850 func CheckLoweredGetClosurePtr(v *ssa.Value) { 4851 entry := v.Block.Func.Entry 4852 if entry != v.Block || entry.Values[0] != v { 4853 Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v) 4854 } 4855 } 4856 4857 // AutoVar returns a *Node and int64 representing the auto variable and offset within it 4858 // where v should be spilled. 4859 func AutoVar(v *ssa.Value) (*Node, int64) { 4860 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot) 4861 if v.Type.Size() > loc.Type.Size() { 4862 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type) 4863 } 4864 return loc.N.(*Node), loc.Off 4865 } 4866 4867 func AddrAuto(a *obj.Addr, v *ssa.Value) { 4868 n, off := AutoVar(v) 4869 a.Type = obj.TYPE_MEM 4870 a.Sym = n.Sym.Linksym() 4871 a.Reg = int16(thearch.REGSP) 4872 a.Offset = n.Xoffset + off 4873 if n.Class() == PPARAM || n.Class() == PPARAMOUT { 4874 a.Name = obj.NAME_PARAM 4875 } else { 4876 a.Name = obj.NAME_AUTO 4877 } 4878 } 4879 4880 func (s *SSAGenState) AddrScratch(a *obj.Addr) { 4881 if s.ScratchFpMem == nil { 4882 panic("no scratch memory available; forgot to declare usesScratch for Op?") 4883 } 4884 a.Type = obj.TYPE_MEM 4885 a.Name = obj.NAME_AUTO 4886 a.Sym = s.ScratchFpMem.Sym.Linksym() 4887 a.Reg = int16(thearch.REGSP) 4888 a.Offset = s.ScratchFpMem.Xoffset 4889 } 4890 4891 func (s *SSAGenState) Call(v *ssa.Value) *obj.Prog { 4892 idx, ok := s.stackMapIndex[v] 4893 if !ok { 4894 Fatalf("missing stack map index for %v", v.LongString()) 4895 } 4896 p := s.Prog(obj.APCDATA) 4897 Addrconst(&p.From, objabi.PCDATA_StackMapIndex) 4898 Addrconst(&p.To, int64(idx)) 4899 4900 if sym, _ := v.Aux.(*obj.LSym); sym == Deferreturn { 4901 // Deferred calls will appear to be returning to 4902 // the CALL deferreturn(SB) that we are about to emit. 4903 // However, the stack trace code will show the line 4904 // of the instruction byte before the return PC. 4905 // To avoid that being an unrelated instruction, 4906 // insert an actual hardware NOP that will have the right line number. 4907 // This is different from obj.ANOP, which is a virtual no-op 4908 // that doesn't make it into the instruction stream. 4909 thearch.Ginsnop(s.pp) 4910 } 4911 4912 p = s.Prog(obj.ACALL) 4913 if sym, ok := v.Aux.(*obj.LSym); ok { 4914 p.To.Type = obj.TYPE_MEM 4915 p.To.Name = obj.NAME_EXTERN 4916 p.To.Sym = sym 4917 } else { 4918 // TODO(mdempsky): Can these differences be eliminated? 4919 switch thearch.LinkArch.Family { 4920 case sys.AMD64, sys.I386, sys.PPC64, sys.S390X: 4921 p.To.Type = obj.TYPE_REG 4922 case sys.ARM, sys.ARM64, sys.MIPS, sys.MIPS64: 4923 p.To.Type = obj.TYPE_MEM 4924 default: 4925 Fatalf("unknown indirect call family") 4926 } 4927 p.To.Reg = v.Args[0].Reg() 4928 } 4929 if s.maxarg < v.AuxInt { 4930 s.maxarg = v.AuxInt 4931 } 4932 return p 4933 } 4934 4935 // fieldIdx finds the index of the field referred to by the ODOT node n. 4936 func fieldIdx(n *Node) int { 4937 t := n.Left.Type 4938 f := n.Sym 4939 if !t.IsStruct() { 4940 panic("ODOT's LHS is not a struct") 4941 } 4942 4943 var i int 4944 for _, t1 := range t.Fields().Slice() { 4945 if t1.Sym != f { 4946 i++ 4947 continue 4948 } 4949 if t1.Offset != n.Xoffset { 4950 panic("field offset doesn't match") 4951 } 4952 return i 4953 } 4954 panic(fmt.Sprintf("can't find field in expr %v\n", n)) 4955 4956 // TODO: keep the result of this function somewhere in the ODOT Node 4957 // so we don't have to recompute it each time we need it. 4958 } 4959 4960 // ssafn holds frontend information about a function that the backend is processing. 4961 // It also exports a bunch of compiler services for the ssa backend. 4962 type ssafn struct { 4963 curfn *Node 4964 strings map[string]interface{} // map from constant string to data symbols 4965 scratchFpMem *Node // temp for floating point register / memory moves on some architectures 4966 stksize int64 // stack size for current frame 4967 stkptrsize int64 // prefix of stack containing pointers 4968 log bool 4969 } 4970 4971 // StringData returns a symbol (a *types.Sym wrapped in an interface) which 4972 // is the data component of a global string constant containing s. 4973 func (e *ssafn) StringData(s string) interface{} { 4974 if aux, ok := e.strings[s]; ok { 4975 return aux 4976 } 4977 if e.strings == nil { 4978 e.strings = make(map[string]interface{}) 4979 } 4980 data := stringsym(s) 4981 e.strings[s] = data 4982 return data 4983 } 4984 4985 func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode { 4986 n := tempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list 4987 return n 4988 } 4989 4990 func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { 4991 n := name.N.(*Node) 4992 ptrType := types.NewPtr(types.Types[TUINT8]) 4993 lenType := types.Types[TINT] 4994 if n.Class() == PAUTO && !n.Addrtaken() { 4995 // Split this string up into two separate variables. 4996 p := e.splitSlot(&name, ".ptr", 0, ptrType) 4997 l := e.splitSlot(&name, ".len", ptrType.Size(), lenType) 4998 return p, l 4999 } 5000 // Return the two parts of the larger variable. 5001 return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)} 5002 } 5003 5004 func (e *ssafn) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { 5005 n := name.N.(*Node) 5006 t := types.NewPtr(types.Types[TUINT8]) 5007 if n.Class() == PAUTO && !n.Addrtaken() { 5008 // Split this interface up into two separate variables. 5009 f := ".itab" 5010 if n.Type.IsEmptyInterface() { 5011 f = ".type" 5012 } 5013 c := e.splitSlot(&name, f, 0, t) 5014 d := e.splitSlot(&name, ".data", t.Size(), t) 5015 return c, d 5016 } 5017 // Return the two parts of the larger variable. 5018 return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)} 5019 } 5020 5021 func (e *ssafn) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) { 5022 n := name.N.(*Node) 5023 ptrType := types.NewPtr(name.Type.ElemType()) 5024 lenType := types.Types[TINT] 5025 if n.Class() == PAUTO && !n.Addrtaken() { 5026 // Split this slice up into three separate variables. 5027 p := e.splitSlot(&name, ".ptr", 0, ptrType) 5028 l := e.splitSlot(&name, ".len", ptrType.Size(), lenType) 5029 c := e.splitSlot(&name, ".cap", ptrType.Size()+lenType.Size(), lenType) 5030 return p, l, c 5031 } 5032 // Return the three parts of the larger variable. 5033 return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, 5034 ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}, 5035 ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)} 5036 } 5037 5038 func (e *ssafn) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { 5039 n := name.N.(*Node) 5040 s := name.Type.Size() / 2 5041 var t *types.Type 5042 if s == 8 { 5043 t = types.Types[TFLOAT64] 5044 } else { 5045 t = types.Types[TFLOAT32] 5046 } 5047 if n.Class() == PAUTO && !n.Addrtaken() { 5048 // Split this complex up into two separate variables. 5049 r := e.splitSlot(&name, ".real", 0, t) 5050 i := e.splitSlot(&name, ".imag", t.Size(), t) 5051 return r, i 5052 } 5053 // Return the two parts of the larger variable. 5054 return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s} 5055 } 5056 5057 func (e *ssafn) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) { 5058 n := name.N.(*Node) 5059 var t *types.Type 5060 if name.Type.IsSigned() { 5061 t = types.Types[TINT32] 5062 } else { 5063 t = types.Types[TUINT32] 5064 } 5065 if n.Class() == PAUTO && !n.Addrtaken() { 5066 // Split this int64 up into two separate variables. 5067 if thearch.LinkArch.ByteOrder == binary.BigEndian { 5068 return e.splitSlot(&name, ".hi", 0, t), e.splitSlot(&name, ".lo", t.Size(), types.Types[TUINT32]) 5069 } 5070 return e.splitSlot(&name, ".hi", t.Size(), t), e.splitSlot(&name, ".lo", 0, types.Types[TUINT32]) 5071 } 5072 // Return the two parts of the larger variable. 5073 if thearch.LinkArch.ByteOrder == binary.BigEndian { 5074 return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off + 4} 5075 } 5076 return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: types.Types[TUINT32], Off: name.Off} 5077 } 5078 5079 func (e *ssafn) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot { 5080 n := name.N.(*Node) 5081 st := name.Type 5082 ft := st.FieldType(i) 5083 var offset int64 5084 for f := 0; f < i; f++ { 5085 offset += st.FieldType(f).Size() 5086 } 5087 if n.Class() == PAUTO && !n.Addrtaken() { 5088 // Note: the _ field may appear several times. But 5089 // have no fear, identically-named but distinct Autos are 5090 // ok, albeit maybe confusing for a debugger. 5091 return e.splitSlot(&name, "."+st.FieldName(i), offset, ft) 5092 } 5093 return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)} 5094 } 5095 5096 func (e *ssafn) SplitArray(name ssa.LocalSlot) ssa.LocalSlot { 5097 n := name.N.(*Node) 5098 at := name.Type 5099 if at.NumElem() != 1 { 5100 Fatalf("bad array size") 5101 } 5102 et := at.ElemType() 5103 if n.Class() == PAUTO && !n.Addrtaken() { 5104 return e.splitSlot(&name, "[0]", 0, et) 5105 } 5106 return ssa.LocalSlot{N: n, Type: et, Off: name.Off} 5107 } 5108 5109 func (e *ssafn) DerefItab(it *obj.LSym, offset int64) *obj.LSym { 5110 return itabsym(it, offset) 5111 } 5112 5113 // splitSlot returns a slot representing the data of parent starting at offset. 5114 func (e *ssafn) splitSlot(parent *ssa.LocalSlot, suffix string, offset int64, t *types.Type) ssa.LocalSlot { 5115 s := &types.Sym{Name: parent.N.(*Node).Sym.Name + suffix, Pkg: localpkg} 5116 5117 n := new(Node) 5118 n.Name = new(Name) 5119 n.Op = ONAME 5120 n.Pos = parent.N.(*Node).Pos 5121 n.Orig = n 5122 5123 s.Def = asTypesNode(n) 5124 asNode(s.Def).Name.SetUsed(true) 5125 n.Sym = s 5126 n.Type = t 5127 n.SetClass(PAUTO) 5128 n.SetAddable(true) 5129 n.Esc = EscNever 5130 n.Name.Curfn = e.curfn 5131 e.curfn.Func.Dcl = append(e.curfn.Func.Dcl, n) 5132 dowidth(t) 5133 return ssa.LocalSlot{N: n, Type: t, Off: 0, SplitOf: parent, SplitOffset: offset} 5134 } 5135 5136 func (e *ssafn) CanSSA(t *types.Type) bool { 5137 return canSSAType(t) 5138 } 5139 5140 func (e *ssafn) Line(pos src.XPos) string { 5141 return linestr(pos) 5142 } 5143 5144 // Log logs a message from the compiler. 5145 func (e *ssafn) Logf(msg string, args ...interface{}) { 5146 if e.log { 5147 fmt.Printf(msg, args...) 5148 } 5149 } 5150 5151 func (e *ssafn) Log() bool { 5152 return e.log 5153 } 5154 5155 // Fatal reports a compiler error and exits. 5156 func (e *ssafn) Fatalf(pos src.XPos, msg string, args ...interface{}) { 5157 lineno = pos 5158 Fatalf(msg, args...) 5159 } 5160 5161 // Warnl reports a "warning", which is usually flag-triggered 5162 // logging output for the benefit of tests. 5163 func (e *ssafn) Warnl(pos src.XPos, fmt_ string, args ...interface{}) { 5164 Warnl(pos, fmt_, args...) 5165 } 5166 5167 func (e *ssafn) Debug_checknil() bool { 5168 return Debug_checknil != 0 5169 } 5170 5171 func (e *ssafn) Debug_wb() bool { 5172 return Debug_wb != 0 5173 } 5174 5175 func (e *ssafn) UseWriteBarrier() bool { 5176 return use_writebarrier 5177 } 5178 5179 func (e *ssafn) Syslook(name string) *obj.LSym { 5180 switch name { 5181 case "goschedguarded": 5182 return goschedguarded 5183 case "writeBarrier": 5184 return writeBarrier 5185 case "writebarrierptr": 5186 return writebarrierptr 5187 case "typedmemmove": 5188 return typedmemmove 5189 case "typedmemclr": 5190 return typedmemclr 5191 } 5192 Fatalf("unknown Syslook func %v", name) 5193 return nil 5194 } 5195 5196 func (n *Node) Typ() *types.Type { 5197 return n.Type 5198 } 5199 func (n *Node) StorageClass() ssa.StorageClass { 5200 switch n.Class() { 5201 case PPARAM: 5202 return ssa.ClassParam 5203 case PPARAMOUT: 5204 return ssa.ClassParamOut 5205 case PAUTO: 5206 return ssa.ClassAuto 5207 default: 5208 Fatalf("untranslateable storage class for %v: %s", n, n.Class()) 5209 return 0 5210 } 5211 }