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