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