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.
14 "cmd/compile/internal/ssa"
21 var ssaConfig *ssa.Config
24 func initssa() *ssa.Config {
25 ssaExp.unimplemented = false
26 ssaExp.mustImplement = true
28 ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
33 func shouldssa(fn *Node) bool {
34 switch Thearch.LinkArch.Name {
36 // Only available for testing.
37 if os.Getenv("SSATEST") == "" {
40 // Generally available.
47 // Environment variable control of SSA CG
48 // 1. IF GOSSAFUNC == current function name THEN
49 // compile this function with SSA and log output to ssa.html
51 // 2. IF GOSSAHASH == "" THEN
52 // compile this function (and everything else) with SSA
54 // 3. IF GOSSAHASH == "n" or "N"
55 // IF GOSSAPKG == current package name THEN
56 // compile this function (and everything in this package) with SSA
58 // use the old back end for this function.
59 // This is for compatibility with existing test harness and should go away.
61 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
62 // compile this function with SSA
64 // compile this function with the old back end.
66 // Plan is for 3 to be removed when the tests are revised.
67 // SSA is now default, and is disabled by setting
68 // GOSSAHASH to n or N, or selectively with strings of
71 name := fn.Func.Nname.Sym.Name
73 funcname := os.Getenv("GOSSAFUNC")
75 // If GOSSAFUNC is set, compile only that function.
76 return name == funcname
79 pkg := os.Getenv("GOSSAPKG")
81 // If GOSSAPKG is set, compile only that package.
82 return localpkg.Name == pkg
85 return initssa().DebugHashMatch("GOSSAHASH", name)
88 // buildssa builds an SSA function.
89 func buildssa(fn *Node) *ssa.Func {
90 name := fn.Func.Nname.Sym.Name
91 printssa := name == os.Getenv("GOSSAFUNC")
93 fmt.Println("generating SSA for", name)
94 dumplist("buildssa-enter", fn.Func.Enter)
95 dumplist("buildssa-body", fn.Nbody)
96 dumplist("buildssa-exit", fn.Func.Exit)
100 s.pushLine(fn.Lineno)
103 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
104 s.cgoUnsafeArgs = true
106 if fn.Func.Pragma&Nowritebarrier != 0 {
111 fn.Func.WBLineno = s.WBLineno
114 // TODO(khr): build config just once at the start of the compiler binary
116 ssaExp.log = printssa
119 s.f = s.config.NewFunc()
121 s.exitCode = fn.Func.Exit
122 s.panics = map[funcLine]*ssa.Block{}
124 if name == os.Getenv("GOSSAFUNC") {
125 // TODO: tempfile? it is handy to have the location
126 // of this file be stable, so you can just reload in the browser.
127 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
128 // TODO: generate and print a mapping from nodes to values and blocks
132 s.config.HTML.Close()
136 // Allocate starting block
137 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
139 // Allocate starting values
140 s.labels = map[string]*ssaLabel{}
141 s.labeledNodes = map[*Node]*ssaLabel{}
142 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
143 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
144 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
146 s.startBlock(s.f.Entry)
147 s.vars[&memVar] = s.startmem
149 s.varsyms = map[*Node]interface{}{}
151 // Generate addresses of local declarations
152 s.decladdrs = map[*Node]*ssa.Value{}
153 for _, n := range fn.Func.Dcl {
155 case PPARAM, PPARAMOUT:
156 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
157 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
158 if n.Class == PPARAMOUT && s.canSSA(n) {
159 // Save ssa-able PPARAMOUT variables so we can
160 // store them back to the stack at the end of
162 s.returns = append(s.returns, n)
164 if n.Class == PPARAM && s.canSSA(n) && n.Type.IsPtrShaped() {
165 s.ptrargs = append(s.ptrargs, n)
166 n.SetNotLiveAtEnd(true) // SSA takes care of this explicitly
169 // processed at each use, to prevent Addr coming
172 // moved to heap - already handled by frontend
174 // local function - already handled by frontend
176 s.Unimplementedf("local variable with class %s unimplemented", classnames[n.Class])
180 // Convert the AST-based IR to the SSA-based IR
181 s.stmts(fn.Func.Enter)
184 // fallthrough to exit
185 if s.curBlock != nil {
186 s.pushLine(fn.Func.Endlineno)
191 // Check that we used all labels
192 for name, lab := range s.labels {
193 if !lab.used() && !lab.reported {
194 yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
197 if lab.used() && !lab.defined() && !lab.reported {
198 yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
203 // Check any forward gotos. Non-forward gotos have already been checked.
204 for _, n := range s.fwdGotos {
205 lab := s.labels[n.Left.Sym.Name]
206 // If the label is undefined, we have already have printed an error.
208 s.checkgoto(n, lab.defNode)
217 prelinkNumvars := s.f.NumValues()
218 sparseDefState := s.locatePotentialPhiFunctions(fn)
220 // Link up variable uses to variable definitions
221 s.linkForwardReferences(sparseDefState)
223 if ssa.BuildStats > 0 {
224 s.f.LogStat("build", s.f.NumBlocks(), "blocks", prelinkNumvars, "vars_before",
225 s.f.NumValues(), "vars_after", prelinkNumvars*s.f.NumBlocks(), "ssa_phi_loc_cutoff_score")
228 // Don't carry reference this around longer than necessary
231 // Main call to ssa package to compile function
238 // configuration (arch) information
241 // function we're building
244 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
245 labels map[string]*ssaLabel
246 labeledNodes map[*Node]*ssaLabel
248 // gotos that jump forward; required for deferred checkgoto calls
250 // Code that must precede any return
251 // (e.g., copying value of heap-escaped paramout back to true paramout)
254 // unlabeled break and continue statement tracking
255 breakTo *ssa.Block // current target for plain break statement
256 continueTo *ssa.Block // current target for plain continue statement
258 // current location where we're interpreting the AST
261 // variable assignments in the current block (map from variable symbol to ssa value)
262 // *Node is the unique identifier (an ONAME Node) for the variable.
263 vars map[*Node]*ssa.Value
265 // all defined variables at the end of each block. Indexed by block ID.
266 defvars []map[*Node]*ssa.Value
268 // addresses of PPARAM and PPARAMOUT variables.
269 decladdrs map[*Node]*ssa.Value
271 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
272 varsyms map[*Node]interface{}
274 // starting values. Memory, stack pointer, and globals pointer
279 // line number stack. The current line number is top of stack
282 // list of panic calls by function name and line number.
283 // Used to deduplicate panic calls.
284 panics map[funcLine]*ssa.Block
286 // list of FwdRef values.
289 // list of PPARAMOUT (return) variables.
292 // list of PPARAM SSA-able pointer-shaped args. We ensure these are live
293 // throughout the function to help users avoid premature finalizers.
298 WBLineno int32 // line number of first write barrier. 0=no write barriers
301 type funcLine struct {
306 type ssaLabel struct {
307 target *ssa.Block // block identified by this label
308 breakTarget *ssa.Block // block to break to in control flow node identified by this label
309 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
310 defNode *Node // label definition Node (OLABEL)
311 // Label use Node (OGOTO, OBREAK, OCONTINUE).
312 // Used only for error detection and reporting.
313 // There might be multiple uses, but we only need to track one.
315 reported bool // reported indicates whether an error has already been reported for this label
318 // defined reports whether the label has a definition (OLABEL node).
319 func (l *ssaLabel) defined() bool { return l.defNode != nil }
321 // used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
322 func (l *ssaLabel) used() bool { return l.useNode != nil }
324 // label returns the label associated with sym, creating it if necessary.
325 func (s *state) label(sym *Sym) *ssaLabel {
326 lab := s.labels[sym.Name]
329 s.labels[sym.Name] = lab
334 func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
335 func (s *state) Log() bool { return s.config.Log() }
336 func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
337 func (s *state) Unimplementedf(msg string, args ...interface{}) {
338 s.config.Unimplementedf(s.peekLine(), msg, args...)
340 func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
341 func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
344 // dummy node for the memory variable
345 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
347 // dummy nodes for temporary variables
348 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
349 lenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "len"}}
350 newlenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "newlen"}}
351 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
352 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
353 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
354 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
355 deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
358 // startBlock sets the current block we're generating code in to b.
359 func (s *state) startBlock(b *ssa.Block) {
360 if s.curBlock != nil {
361 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
364 s.vars = map[*Node]*ssa.Value{}
367 // endBlock marks the end of generating code for the current block.
368 // Returns the (former) current block. Returns nil if there is no current
369 // block, i.e. if no code flows to the current execution point.
370 func (s *state) endBlock() *ssa.Block {
375 for len(s.defvars) <= int(b.ID) {
376 s.defvars = append(s.defvars, nil)
378 s.defvars[b.ID] = s.vars
381 b.Line = s.peekLine()
385 // pushLine pushes a line number on the line number stack.
386 func (s *state) pushLine(line int32) {
387 s.line = append(s.line, line)
390 // popLine pops the top of the line number stack.
391 func (s *state) popLine() {
392 s.line = s.line[:len(s.line)-1]
395 // peekLine peek the top of the line number stack.
396 func (s *state) peekLine() int32 {
397 return s.line[len(s.line)-1]
400 func (s *state) Error(msg string, args ...interface{}) {
401 yyerrorl(s.peekLine(), msg, args...)
404 // newValue0 adds a new value with no arguments to the current block.
405 func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
406 return s.curBlock.NewValue0(s.peekLine(), op, t)
409 // newValue0A adds a new value with no arguments and an aux value to the current block.
410 func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
411 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
414 // newValue0I adds a new value with no arguments and an auxint value to the current block.
415 func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
416 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
419 // newValue1 adds a new value with one argument to the current block.
420 func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
421 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
424 // newValue1A adds a new value with one argument and an aux value to the current block.
425 func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
426 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
429 // newValue1I adds a new value with one argument and an auxint value to the current block.
430 func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
431 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
434 // newValue2 adds a new value with two arguments to the current block.
435 func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
436 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
439 // newValue2I adds a new value with two arguments and an auxint value to the current block.
440 func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
441 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
444 // newValue3 adds a new value with three arguments to the current block.
445 func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
446 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
449 // newValue3I adds a new value with three arguments and an auxint value to the current block.
450 func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
451 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
454 // entryNewValue0 adds a new value with no arguments to the entry block.
455 func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
456 return s.f.Entry.NewValue0(s.peekLine(), op, t)
459 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
460 func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
461 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
464 // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
465 func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
466 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
469 // entryNewValue1 adds a new value with one argument to the entry block.
470 func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
471 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
474 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
475 func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
476 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
479 // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
480 func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
481 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
484 // entryNewValue2 adds a new value with two arguments to the entry block.
485 func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
486 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
489 // const* routines add a new const value to the entry block.
490 func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) }
491 func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) }
492 func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) }
493 func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
494 func (s *state) constBool(c bool) *ssa.Value {
495 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
497 func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
498 return s.f.ConstInt8(s.peekLine(), t, c)
500 func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
501 return s.f.ConstInt16(s.peekLine(), t, c)
503 func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
504 return s.f.ConstInt32(s.peekLine(), t, c)
506 func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
507 return s.f.ConstInt64(s.peekLine(), t, c)
509 func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
510 return s.f.ConstFloat32(s.peekLine(), t, c)
512 func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
513 return s.f.ConstFloat64(s.peekLine(), t, c)
515 func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
516 if s.config.IntSize == 8 {
517 return s.constInt64(t, c)
519 if int64(int32(c)) != c {
520 s.Fatalf("integer constant too big %d", c)
522 return s.constInt32(t, int32(c))
525 func (s *state) stmts(a Nodes) {
526 for _, x := range a.Slice() {
531 // ssaStmtList converts the statement n to SSA and adds it to s.
532 func (s *state) stmtList(l Nodes) {
533 for _, n := range l.Slice() {
538 // ssaStmt converts the statement n to SSA and adds it to s.
539 func (s *state) stmt(n *Node) {
543 // If s.curBlock is nil, then we're about to generate dead code.
544 // We can't just short-circuit here, though,
545 // because we check labels and gotos as part of SSA generation.
546 // Provide a block for the dead code so that we don't have
547 // to add special cases everywhere else.
548 if s.curBlock == nil {
549 dead := s.f.NewBlock(ssa.BlockPlain)
560 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
562 // Expression statements
563 case OCALLFUNC, OCALLMETH, OCALLINTER:
564 s.call(n, callNormal)
565 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
566 (compiling_runtime && n.Left.Sym.Name == "throw" ||
567 n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
570 b.Kind = ssa.BlockExit
572 // TODO: never rewrite OPANIC to OCALLFUNC in the
573 // first place. Need to wait until all backends
577 s.call(n.Left, callDefer)
579 s.call(n.Left, callGo)
582 res, resok := s.dottype(n.Rlist.First(), true)
583 s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0)
584 s.assign(n.List.Second(), resok, false, false, n.Lineno, 0)
588 if n.Left.Class == PAUTOHEAP {
596 // Empty identifier is valid but useless.
597 // See issues 11589, 11593.
603 // Associate label with its control flow node, if any
604 if ctl := n.Name.Defn; ctl != nil {
606 case OFOR, OSWITCH, OSELECT:
607 s.labeledNodes[ctl] = lab
614 s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
617 // The label might already have a target block via a goto.
618 if lab.target == nil {
619 lab.target = s.f.NewBlock(ssa.BlockPlain)
622 // go to that label (we pretend "label:" is preceded by "goto label")
624 b.AddEdgeTo(lab.target)
625 s.startBlock(lab.target)
631 if lab.target == nil {
632 lab.target = s.f.NewBlock(ssa.BlockPlain)
639 s.checkgoto(n, lab.defNode)
641 s.fwdGotos = append(s.fwdGotos, n)
645 b.AddEdgeTo(lab.target)
648 // Check whether we can generate static data rather than code.
649 // If so, ignore n and defer data generation until codegen.
650 // Failure to do this causes writes to readonly symbols.
651 if gen_as_init(n, true) {
653 if s.f.StaticData != nil {
654 data = s.f.StaticData.([]*Node)
656 s.f.StaticData = append(data, n)
660 if n.Left == n.Right && n.Left.Op == ONAME {
661 // An x=x assignment. No point in doing anything
662 // here. In addition, skipping this assignment
663 // prevents generating:
666 // which is bad because x is incorrectly considered
667 // dead before the vardef. See issue #14904.
682 case OSTRUCTLIT, OARRAYLIT:
683 // All literals with nonzero fields have already been
684 // rewritten during walk. Any that remain are just T{}
685 // or equivalents. Use the zero value.
687 Fatalf("literal with nonzero value in SSA: %v", rhs)
691 // If we're writing the result of an append back to the same slice,
692 // handle it specially to avoid write barriers on the fast (non-growth) path.
693 // If the slice can be SSA'd, it'll be on the stack,
694 // so there will be no write barriers,
695 // so there's no need to attempt to prevent them.
696 if samesafeexpr(n.Left, rhs.List.First()) && !s.canSSA(n.Left) {
703 needwb := n.Op == OASWB && rhs != nil
704 deref := !canSSAType(t)
707 r = nil // Signal assign to use OpZero.
709 r = s.addr(rhs, false)
718 if rhs != nil && rhs.Op == OAPPEND {
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.
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 [:...]
737 // TODO: detect defaults for len/cap also.
738 // Currently doesn't really work because (*p)[:len(*p)] appears here as:
741 //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) {
744 //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) {
758 s.assign(n.Left, r, needwb, deref, n.Lineno, skip)
761 bThen := s.f.NewBlock(ssa.BlockPlain)
762 bEnd := s.f.NewBlock(ssa.BlockPlain)
764 if n.Rlist.Len() != 0 {
765 bElse = s.f.NewBlock(ssa.BlockPlain)
766 s.condBranch(n.Left, bThen, bElse, n.Likely)
768 s.condBranch(n.Left, bThen, bEnd, n.Likely)
773 if b := s.endBlock(); b != nil {
777 if n.Rlist.Len() != 0 {
780 if b := s.endBlock(); b != nil {
792 b.Kind = ssa.BlockRetJmp // override BlockRet
795 case OCONTINUE, OBREAK:
807 // plain break/continue
809 s.Error("%s is not in a loop", op)
812 // nothing to do; "to" is already the correct target
814 // labeled break/continue; look up the target
821 s.Error("%s label not defined: %v", op, sym)
827 to = lab.continueTarget
832 // Valid label but not usable with a break/continue here, e.g.:
838 s.Error("invalid %s label %v", op, sym)
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)
854 // first, jump to condition test
858 // generate code to test condition
861 s.condBranch(n.Left, bBody, bEnd, 1)
864 b.Kind = ssa.BlockPlain
868 // set up for continue/break in body
869 prevContinue := s.continueTo
870 prevBreak := s.breakTo
873 lab := s.labeledNodes[n]
876 lab.continueTarget = bIncr
877 lab.breakTarget = bEnd
884 // tear down continue/break
885 s.continueTo = prevContinue
886 s.breakTo = prevBreak
888 lab.continueTarget = nil
889 lab.breakTarget = nil
892 // done with body, goto incr
893 if b := s.endBlock(); b != nil {
902 if b := s.endBlock(); b != nil {
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)
912 prevBreak := s.breakTo
914 lab := s.labeledNodes[n]
917 lab.breakTarget = bEnd
920 // generate body code
923 s.breakTo = prevBreak
925 lab.breakTarget = nil
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 {
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())
947 // Insert a varlive op to record that a variable is still live.
948 if !n.Left.Addrtaken {
949 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
951 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
958 s.Unimplementedf("unhandled stmt %s", n.Op)
962 // exit processes any code that needs to be generated just before returning.
963 // It returns a BlockRet block that ends the control flow. Its control value
964 // will be set to the final memory state.
965 func (s *state) exit() *ssa.Block {
967 s.rtcall(Deferreturn, true, nil)
970 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
971 // variables back to the stack.
974 // Store SSAable PPARAMOUT variables back to stack locations.
975 for _, n := range s.returns {
976 addr := s.decladdrs[n]
977 val := s.variable(n, n.Type)
978 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
979 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
980 // TODO: if val is ever spilled, we'd like to use the
981 // PPARAMOUT slot for spilling it. That won't happen
985 // Keep input pointer args live until the return. This is a bandaid
986 // fix for 1.7 for what will become in 1.8 explicit runtime.KeepAlive calls.
987 // For <= 1.7 we guarantee that pointer input arguments live to the end of
988 // the function to prevent premature (from the user's point of view)
989 // execution of finalizers. See issue 15277.
990 // TODO: remove for 1.8?
991 for _, n := range s.ptrargs {
992 s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
998 b.Kind = ssa.BlockRet
1003 type opAndType struct {
1008 var opToSSA = map[opAndType]ssa.Op{
1009 opAndType{OADD, TINT8}: ssa.OpAdd8,
1010 opAndType{OADD, TUINT8}: ssa.OpAdd8,
1011 opAndType{OADD, TINT16}: ssa.OpAdd16,
1012 opAndType{OADD, TUINT16}: ssa.OpAdd16,
1013 opAndType{OADD, TINT32}: ssa.OpAdd32,
1014 opAndType{OADD, TUINT32}: ssa.OpAdd32,
1015 opAndType{OADD, TPTR32}: ssa.OpAdd32,
1016 opAndType{OADD, TINT64}: ssa.OpAdd64,
1017 opAndType{OADD, TUINT64}: ssa.OpAdd64,
1018 opAndType{OADD, TPTR64}: ssa.OpAdd64,
1019 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
1020 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
1022 opAndType{OSUB, TINT8}: ssa.OpSub8,
1023 opAndType{OSUB, TUINT8}: ssa.OpSub8,
1024 opAndType{OSUB, TINT16}: ssa.OpSub16,
1025 opAndType{OSUB, TUINT16}: ssa.OpSub16,
1026 opAndType{OSUB, TINT32}: ssa.OpSub32,
1027 opAndType{OSUB, TUINT32}: ssa.OpSub32,
1028 opAndType{OSUB, TINT64}: ssa.OpSub64,
1029 opAndType{OSUB, TUINT64}: ssa.OpSub64,
1030 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
1031 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
1033 opAndType{ONOT, TBOOL}: ssa.OpNot,
1035 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
1036 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
1037 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
1038 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
1039 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
1040 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
1041 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
1042 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
1043 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
1044 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
1046 opAndType{OCOM, TINT8}: ssa.OpCom8,
1047 opAndType{OCOM, TUINT8}: ssa.OpCom8,
1048 opAndType{OCOM, TINT16}: ssa.OpCom16,
1049 opAndType{OCOM, TUINT16}: ssa.OpCom16,
1050 opAndType{OCOM, TINT32}: ssa.OpCom32,
1051 opAndType{OCOM, TUINT32}: ssa.OpCom32,
1052 opAndType{OCOM, TINT64}: ssa.OpCom64,
1053 opAndType{OCOM, TUINT64}: ssa.OpCom64,
1055 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
1056 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
1057 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
1058 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
1060 opAndType{OMUL, TINT8}: ssa.OpMul8,
1061 opAndType{OMUL, TUINT8}: ssa.OpMul8,
1062 opAndType{OMUL, TINT16}: ssa.OpMul16,
1063 opAndType{OMUL, TUINT16}: ssa.OpMul16,
1064 opAndType{OMUL, TINT32}: ssa.OpMul32,
1065 opAndType{OMUL, TUINT32}: ssa.OpMul32,
1066 opAndType{OMUL, TINT64}: ssa.OpMul64,
1067 opAndType{OMUL, TUINT64}: ssa.OpMul64,
1068 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
1069 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
1071 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
1072 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
1074 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
1075 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
1076 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
1077 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
1078 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
1079 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
1081 opAndType{ODIV, TINT8}: ssa.OpDiv8,
1082 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
1083 opAndType{ODIV, TINT16}: ssa.OpDiv16,
1084 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
1085 opAndType{ODIV, TINT32}: ssa.OpDiv32,
1086 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
1087 opAndType{ODIV, TINT64}: ssa.OpDiv64,
1088 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
1090 opAndType{OMOD, TINT8}: ssa.OpMod8,
1091 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1092 opAndType{OMOD, TINT16}: ssa.OpMod16,
1093 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1094 opAndType{OMOD, TINT32}: ssa.OpMod32,
1095 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1096 opAndType{OMOD, TINT64}: ssa.OpMod64,
1097 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1099 opAndType{OAND, TINT8}: ssa.OpAnd8,
1100 opAndType{OAND, TUINT8}: ssa.OpAnd8,
1101 opAndType{OAND, TINT16}: ssa.OpAnd16,
1102 opAndType{OAND, TUINT16}: ssa.OpAnd16,
1103 opAndType{OAND, TINT32}: ssa.OpAnd32,
1104 opAndType{OAND, TUINT32}: ssa.OpAnd32,
1105 opAndType{OAND, TINT64}: ssa.OpAnd64,
1106 opAndType{OAND, TUINT64}: ssa.OpAnd64,
1108 opAndType{OOR, TINT8}: ssa.OpOr8,
1109 opAndType{OOR, TUINT8}: ssa.OpOr8,
1110 opAndType{OOR, TINT16}: ssa.OpOr16,
1111 opAndType{OOR, TUINT16}: ssa.OpOr16,
1112 opAndType{OOR, TINT32}: ssa.OpOr32,
1113 opAndType{OOR, TUINT32}: ssa.OpOr32,
1114 opAndType{OOR, TINT64}: ssa.OpOr64,
1115 opAndType{OOR, TUINT64}: ssa.OpOr64,
1117 opAndType{OXOR, TINT8}: ssa.OpXor8,
1118 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1119 opAndType{OXOR, TINT16}: ssa.OpXor16,
1120 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1121 opAndType{OXOR, TINT32}: ssa.OpXor32,
1122 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1123 opAndType{OXOR, TINT64}: ssa.OpXor64,
1124 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1126 opAndType{OEQ, TBOOL}: ssa.OpEqB,
1127 opAndType{OEQ, TINT8}: ssa.OpEq8,
1128 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1129 opAndType{OEQ, TINT16}: ssa.OpEq16,
1130 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1131 opAndType{OEQ, TINT32}: ssa.OpEq32,
1132 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1133 opAndType{OEQ, TINT64}: ssa.OpEq64,
1134 opAndType{OEQ, TUINT64}: ssa.OpEq64,
1135 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1136 opAndType{OEQ, TSLICE}: ssa.OpEqSlice,
1137 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1138 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1139 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
1140 opAndType{OEQ, TPTR32}: ssa.OpEqPtr,
1141 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
1142 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1143 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
1144 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1145 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
1147 opAndType{ONE, TBOOL}: ssa.OpNeqB,
1148 opAndType{ONE, TINT8}: ssa.OpNeq8,
1149 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1150 opAndType{ONE, TINT16}: ssa.OpNeq16,
1151 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1152 opAndType{ONE, TINT32}: ssa.OpNeq32,
1153 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1154 opAndType{ONE, TINT64}: ssa.OpNeq64,
1155 opAndType{ONE, TUINT64}: ssa.OpNeq64,
1156 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1157 opAndType{ONE, TSLICE}: ssa.OpNeqSlice,
1158 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1159 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1160 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
1161 opAndType{ONE, TPTR32}: ssa.OpNeqPtr,
1162 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
1163 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1164 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
1165 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1166 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
1168 opAndType{OLT, TINT8}: ssa.OpLess8,
1169 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1170 opAndType{OLT, TINT16}: ssa.OpLess16,
1171 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1172 opAndType{OLT, TINT32}: ssa.OpLess32,
1173 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1174 opAndType{OLT, TINT64}: ssa.OpLess64,
1175 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1176 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1177 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
1179 opAndType{OGT, TINT8}: ssa.OpGreater8,
1180 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1181 opAndType{OGT, TINT16}: ssa.OpGreater16,
1182 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1183 opAndType{OGT, TINT32}: ssa.OpGreater32,
1184 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1185 opAndType{OGT, TINT64}: ssa.OpGreater64,
1186 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1187 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1188 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
1190 opAndType{OLE, TINT8}: ssa.OpLeq8,
1191 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1192 opAndType{OLE, TINT16}: ssa.OpLeq16,
1193 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1194 opAndType{OLE, TINT32}: ssa.OpLeq32,
1195 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1196 opAndType{OLE, TINT64}: ssa.OpLeq64,
1197 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1198 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1199 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
1201 opAndType{OGE, TINT8}: ssa.OpGeq8,
1202 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1203 opAndType{OGE, TINT16}: ssa.OpGeq16,
1204 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1205 opAndType{OGE, TINT32}: ssa.OpGeq32,
1206 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1207 opAndType{OGE, TINT64}: ssa.OpGeq64,
1208 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1209 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1210 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
1212 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1213 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1214 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1215 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
1217 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
1220 func (s *state) concreteEtype(t *Type) EType {
1226 if s.config.IntSize == 8 {
1231 if s.config.IntSize == 8 {
1236 if s.config.PtrSize == 8 {
1243 func (s *state) ssaOp(op Op, t *Type) ssa.Op {
1244 etype := s.concreteEtype(t)
1245 x, ok := opToSSA[opAndType{op, etype}]
1247 s.Unimplementedf("unhandled binary op %s %s", op, etype)
1252 func floatForComplex(t *Type) *Type {
1254 return Types[TFLOAT32]
1256 return Types[TFLOAT64]
1260 type opAndTwoTypes struct {
1266 type twoTypes struct {
1271 type twoOpsAndType struct {
1274 intermediateType EType
1277 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1279 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1280 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1281 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1282 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1284 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1285 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1286 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1287 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1289 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1290 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1291 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1292 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1294 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1295 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1296 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1297 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1299 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1300 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1301 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1302 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1304 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1305 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1306 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1307 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1309 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1310 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1311 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1312 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1314 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1315 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1316 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1317 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1320 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1321 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1322 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1323 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1326 // this map is used only for 32-bit arch, and only includes the difference
1327 // on 32-bit arch, don't use int64<->float conversion for uint32
1328 var fpConvOpToSSA32 = map[twoTypes]twoOpsAndType{
1329 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto32F, TUINT32},
1330 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32Uto64F, TUINT32},
1331 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto32U, ssa.OpCopy, TUINT32},
1332 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto32U, ssa.OpCopy, TUINT32},
1335 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1336 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1337 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1338 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1339 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1340 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1341 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1342 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1343 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1345 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1346 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1347 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1348 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1349 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1350 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1351 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1352 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1354 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1355 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1356 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1357 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1358 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1359 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1360 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1361 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1363 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1364 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1365 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1366 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1367 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1368 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1369 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1370 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1372 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1373 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1374 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1375 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1376 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1377 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1378 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1379 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1381 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1382 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1383 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1384 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1385 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1386 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1387 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1388 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1390 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1391 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1392 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1393 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1394 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1395 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1396 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1397 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1399 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1400 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1401 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1402 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1403 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1404 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1405 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1406 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1409 func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
1410 etype1 := s.concreteEtype(t)
1411 etype2 := s.concreteEtype(u)
1412 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1414 s.Unimplementedf("unhandled shift op %s etype=%s/%s", op, etype1, etype2)
1419 func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
1420 etype1 := s.concreteEtype(t)
1421 x, ok := opToSSA[opAndType{op, etype1}]
1423 s.Unimplementedf("unhandled rotate op %s etype=%s", op, etype1)
1428 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
1429 func (s *state) expr(n *Node) *ssa.Value {
1430 if !(n.Op == ONAME || n.Op == OLITERAL && n.Sym != nil) {
1431 // ONAMEs and named OLITERALs have the line number
1432 // of the decl, not the use. See issue 14742.
1433 s.pushLine(n.Lineno)
1440 aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Left.Sym})
1441 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
1443 if n.Class == PFUNC {
1444 // "value" of a function is the address of the function's closure
1445 sym := funcsym(n.Sym)
1446 aux := &ssa.ExternSymbol{Typ: n.Type, Sym: sym}
1447 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
1450 return s.variable(n, n.Type)
1452 addr := s.addr(n, false)
1453 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1455 addr := s.addr(n, false)
1456 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1458 switch u := n.Val().U.(type) {
1461 switch n.Type.Size() {
1463 return s.constInt8(n.Type, int8(i))
1465 return s.constInt16(n.Type, int16(i))
1467 return s.constInt32(n.Type, int32(i))
1469 return s.constInt64(n.Type, i)
1471 s.Fatalf("bad integer size %d", n.Type.Size())
1476 return s.constEmptyString(n.Type)
1478 return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
1480 return s.constBool(u)
1485 return s.constSlice(t)
1486 case t.IsInterface():
1487 return s.constInterface(t)
1489 return s.constNil(t)
1492 switch n.Type.Size() {
1494 return s.constFloat32(n.Type, u.Float32())
1496 return s.constFloat64(n.Type, u.Float64())
1498 s.Fatalf("bad float size %d", n.Type.Size())
1504 switch n.Type.Size() {
1506 pt := Types[TFLOAT32]
1507 return s.newValue2(ssa.OpComplexMake, n.Type,
1508 s.constFloat32(pt, r.Float32()),
1509 s.constFloat32(pt, i.Float32()))
1511 pt := Types[TFLOAT64]
1512 return s.newValue2(ssa.OpComplexMake, n.Type,
1513 s.constFloat64(pt, r.Float64()),
1514 s.constFloat64(pt, i.Float64()))
1516 s.Fatalf("bad float size %d", n.Type.Size())
1521 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
1528 // Assume everything will work out, so set up our return value.
1529 // Anything interesting that happens from here is a fatal.
1532 // Special case for not confusing GC and liveness.
1533 // We don't want pointers accidentally classified
1534 // as not-pointers or vice-versa because of copy
1536 if to.IsPtrShaped() != from.IsPtrShaped() {
1537 return s.newValue2(ssa.OpConvert, to, x, s.mem())
1540 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1543 if to.Etype == TFUNC && from.IsPtrShaped() {
1547 // named <--> unnamed type or typed <--> untyped const
1548 if from.Etype == to.Etype {
1552 // unsafe.Pointer <--> *T
1553 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1559 if from.Width != to.Width {
1560 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1563 if etypesign(from.Etype) != etypesign(to.Etype) {
1564 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype)
1569 // These appear to be fine, but they fail the
1570 // integer constraint below, so okay them here.
1571 // Sample non-integer conversion: map[string]string -> *uint8
1575 if etypesign(from.Etype) == 0 {
1576 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1580 // integer, same width, same sign
1585 ft := n.Left.Type // from type
1586 tt := n.Type // to type
1587 if ft.IsInteger() && tt.IsInteger() {
1589 if tt.Size() == ft.Size() {
1591 } else if tt.Size() < ft.Size() {
1593 switch 10*ft.Size() + tt.Size() {
1595 op = ssa.OpTrunc16to8
1597 op = ssa.OpTrunc32to8
1599 op = ssa.OpTrunc32to16
1601 op = ssa.OpTrunc64to8
1603 op = ssa.OpTrunc64to16
1605 op = ssa.OpTrunc64to32
1607 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1609 } else if ft.IsSigned() {
1611 switch 10*ft.Size() + tt.Size() {
1613 op = ssa.OpSignExt8to16
1615 op = ssa.OpSignExt8to32
1617 op = ssa.OpSignExt8to64
1619 op = ssa.OpSignExt16to32
1621 op = ssa.OpSignExt16to64
1623 op = ssa.OpSignExt32to64
1625 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1629 switch 10*ft.Size() + tt.Size() {
1631 op = ssa.OpZeroExt8to16
1633 op = ssa.OpZeroExt8to32
1635 op = ssa.OpZeroExt8to64
1637 op = ssa.OpZeroExt16to32
1639 op = ssa.OpZeroExt16to64
1641 op = ssa.OpZeroExt32to64
1643 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1646 return s.newValue1(op, n.Type, x)
1649 if ft.IsFloat() || tt.IsFloat() {
1650 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1651 if s.config.IntSize == 4 {
1652 if conv1, ok1 := fpConvOpToSSA32[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]; ok1 {
1657 s.Fatalf("weird float conversion %s -> %s", ft, tt)
1659 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1661 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1662 // normal case, not tripping over unsigned 64
1663 if op1 == ssa.OpCopy {
1664 if op2 == ssa.OpCopy {
1667 return s.newValue1(op2, n.Type, x)
1669 if op2 == ssa.OpCopy {
1670 return s.newValue1(op1, n.Type, x)
1672 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1674 // Tricky 64-bit unsigned cases.
1676 // therefore tt is float32 or float64, and ft is also unsigned
1678 return s.uint64Tofloat32(n, x, ft, tt)
1681 return s.uint64Tofloat64(n, x, ft, tt)
1683 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
1685 // therefore ft is float32 or float64, and tt is unsigned integer
1687 return s.float32ToUint64(n, x, ft, tt)
1690 return s.float64ToUint64(n, x, ft, tt)
1692 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1696 if ft.IsComplex() && tt.IsComplex() {
1698 if ft.Size() == tt.Size() {
1700 } else if ft.Size() == 8 && tt.Size() == 16 {
1701 op = ssa.OpCvt32Fto64F
1702 } else if ft.Size() == 16 && tt.Size() == 8 {
1703 op = ssa.OpCvt64Fto32F
1705 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1707 ftp := floatForComplex(ft)
1708 ttp := floatForComplex(tt)
1709 return s.newValue2(ssa.OpComplexMake, tt,
1710 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1711 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1714 s.Unimplementedf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
1718 res, _ := s.dottype(n, false)
1722 case OLT, OEQ, ONE, OLE, OGE, OGT:
1724 b := s.expr(n.Right)
1725 if n.Left.Type.IsComplex() {
1726 pt := floatForComplex(n.Left.Type)
1727 op := s.ssaOp(OEQ, pt)
1728 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1729 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1730 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1735 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1737 s.Fatalf("ordered complex compare %s", n.Op)
1740 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
1743 b := s.expr(n.Right)
1744 if n.Type.IsComplex() {
1745 mulop := ssa.OpMul64F
1746 addop := ssa.OpAdd64F
1747 subop := ssa.OpSub64F
1748 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1749 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1751 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1752 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1753 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1754 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1756 if pt != wt { // Widen for calculation
1757 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1758 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1759 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1760 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1763 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1764 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1766 if pt != wt { // Narrow to store back
1767 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1768 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1771 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1773 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1777 b := s.expr(n.Right)
1778 if n.Type.IsComplex() {
1779 // TODO this is not executed because the front-end substitutes a runtime call.
1780 // That probably ought to change; with modest optimization the widen/narrow
1781 // conversions could all be elided in larger expression trees.
1782 mulop := ssa.OpMul64F
1783 addop := ssa.OpAdd64F
1784 subop := ssa.OpSub64F
1785 divop := ssa.OpDiv64F
1786 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1787 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1789 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1790 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1791 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1792 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1794 if pt != wt { // Widen for calculation
1795 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1796 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1797 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1798 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1801 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1802 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1803 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1805 // TODO not sure if this is best done in wide precision or narrow
1806 // Double-rounding might be an issue.
1807 // Note that the pre-SSA implementation does the entire calculation
1808 // in wide format, so wide is compatible.
1809 xreal = s.newValue2(divop, wt, xreal, denom)
1810 ximag = s.newValue2(divop, wt, ximag, denom)
1812 if pt != wt { // Narrow to store back
1813 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1814 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1816 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1818 if n.Type.IsFloat() {
1819 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1821 // do a size-appropriate check for zero
1822 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1823 s.check(cmp, panicdivide)
1824 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1828 b := s.expr(n.Right)
1829 // do a size-appropriate check for zero
1830 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1831 s.check(cmp, panicdivide)
1832 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1835 b := s.expr(n.Right)
1836 if n.Type.IsComplex() {
1837 pt := floatForComplex(n.Type)
1838 op := s.ssaOp(n.Op, pt)
1839 return s.newValue2(ssa.OpComplexMake, n.Type,
1840 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1841 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1843 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1844 case OAND, OOR, OHMUL, OXOR:
1846 b := s.expr(n.Right)
1847 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1850 b := s.expr(n.Right)
1851 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
1854 i := n.Right.Int64()
1855 if i <= 0 || i >= n.Type.Size()*8 {
1856 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1858 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
1859 case OANDAND, OOROR:
1860 // To implement OANDAND (and OOROR), we introduce a
1861 // new temporary variable to hold the result. The
1862 // variable is associated with the OANDAND node in the
1863 // s.vars table (normally variables are only
1864 // associated with ONAME nodes). We convert
1871 // Using var in the subsequent block introduces the
1872 // necessary phi variable.
1873 el := s.expr(n.Left)
1877 b.Kind = ssa.BlockIf
1879 // In theory, we should set b.Likely here based on context.
1880 // However, gc only gives us likeliness hints
1881 // in a single place, for plain OIF statements,
1882 // and passing around context is finnicky, so don't bother for now.
1884 bRight := s.f.NewBlock(ssa.BlockPlain)
1885 bResult := s.f.NewBlock(ssa.BlockPlain)
1886 if n.Op == OANDAND {
1888 b.AddEdgeTo(bResult)
1889 } else if n.Op == OOROR {
1890 b.AddEdgeTo(bResult)
1894 s.startBlock(bRight)
1895 er := s.expr(n.Right)
1899 b.AddEdgeTo(bResult)
1901 s.startBlock(bResult)
1902 return s.variable(n, Types[TBOOL])
1905 i := s.expr(n.Right)
1906 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
1911 if n.Type.IsComplex() {
1912 tp := floatForComplex(n.Type)
1913 negop := s.ssaOp(n.Op, tp)
1914 return s.newValue2(ssa.OpComplexMake, n.Type,
1915 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1916 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1918 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1919 case ONOT, OCOM, OSQRT:
1921 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1924 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
1926 return s.expr(n.Left)
1929 return s.addr(n.Left, n.Bounded)
1932 if int(n.Reg) != Thearch.REGSP {
1933 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1936 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1937 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1940 p := s.exprPtr(n.Left, false, n.Lineno)
1941 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1947 return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
1949 p := s.addr(n, false)
1950 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1953 p := s.exprPtr(n.Left, false, n.Lineno)
1954 p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
1955 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1959 case n.Left.Type.IsString():
1961 i := s.expr(n.Right)
1962 i = s.extendIndex(i, Panicindex)
1964 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1965 s.boundsCheck(i, len)
1967 ptrtyp := Ptrto(Types[TUINT8])
1968 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1969 if Isconst(n.Right, CTINT) {
1970 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
1972 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1974 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1975 case n.Left.Type.IsSlice():
1976 p := s.addr(n, false)
1977 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
1978 case n.Left.Type.IsArray():
1979 // TODO: fix when we can SSA arrays of length 1.
1980 p := s.addr(n, false)
1981 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
1983 s.Fatalf("bad type for index %v", n.Left.Type)
1989 case n.Left.Type.IsSlice():
1990 op := ssa.OpSliceLen
1994 return s.newValue1(op, Types[TINT], s.expr(n.Left))
1995 case n.Left.Type.IsString(): // string; not reachable for OCAP
1996 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
1997 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1998 return s.referenceTypeBuiltin(n, s.expr(n.Left))
2000 return s.constInt(Types[TINT], n.Left.Type.NumElem())
2005 if n.Left.Type.IsSlice() {
2006 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
2008 return s.newValue1(ssa.OpStringPtr, n.Type, a)
2013 return s.newValue1(ssa.OpITab, n.Type, a)
2016 tab := s.expr(n.Left)
2017 data := s.expr(n.Right)
2018 // The frontend allows putting things like struct{*byte} in
2019 // the data portion of an eface. But we don't want struct{*byte}
2020 // as a register type because (among other reasons) the liveness
2021 // analysis is confused by the "fat" variables that result from
2022 // such types being spilled.
2023 // So here we ensure that we are selecting the underlying pointer
2024 // when we build an eface.
2025 // TODO: get rid of this now that structs can be SSA'd?
2026 for !data.Type.IsPtrShaped() {
2028 case data.Type.IsArray():
2029 data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
2030 case data.Type.IsStruct():
2031 for i := data.Type.NumFields() - 1; i >= 0; i-- {
2032 f := data.Type.FieldType(i)
2034 // eface type could also be struct{p *byte; q [0]int}
2037 data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
2041 s.Fatalf("type being put into an eface isn't a pointer")
2044 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
2046 case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR:
2048 var i, j, k *ssa.Value
2049 low, high, max := n.SliceBounds()
2051 i = s.extendIndex(s.expr(low), panicslice)
2054 j = s.extendIndex(s.expr(high), panicslice)
2057 k = s.extendIndex(s.expr(max), panicslice)
2059 p, l, c := s.slice(n.Left.Type, v, i, j, k)
2060 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
2065 low, high, _ := n.SliceBounds()
2067 i = s.extendIndex(s.expr(low), panicslice)
2070 j = s.extendIndex(s.expr(high), panicslice)
2072 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
2073 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
2076 if isIntrinsicCall1(n) {
2077 return s.intrinsicCall1(n)
2081 case OCALLINTER, OCALLMETH:
2082 a := s.call(n, callNormal)
2083 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
2086 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
2089 return s.append(n, false)
2092 s.Unimplementedf("unhandled expr %s", n.Op)
2097 // append converts an OAPPEND node to SSA.
2098 // If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
2099 // adds it to s, and returns the Value.
2100 // If inplace is true, it writes the result of the OAPPEND expression n
2101 // back to the slice being appended to, and returns nil.
2102 // inplace MUST be set to false if the slice can be SSA'd.
2103 func (s *state) append(n *Node, inplace bool) *ssa.Value {
2104 // If inplace is false, process as expression "append(s, e1, e2, e3)":
2106 // ptr, len, cap := s
2107 // newlen := len + 3
2108 // if newlen > cap {
2109 // ptr, len, cap = growslice(s, newlen)
2110 // newlen = len + 3 // recalculate to avoid a spill
2112 // // with write barriers, if needed:
2114 // *(ptr+len+1) = e2
2115 // *(ptr+len+2) = e3
2116 // return makeslice(ptr, newlen, cap)
2119 // If inplace is true, process as statement "s = append(s, e1, e2, e3)":
2122 // ptr, len, cap := s
2123 // newlen := len + 3
2124 // if newlen > cap {
2125 // newptr, len, newcap = growslice(ptr, len, cap, newlen)
2126 // vardef(a) // if necessary, advise liveness we are writing a new a
2127 // *a.cap = newcap // write before ptr to avoid a spill
2128 // *a.ptr = newptr // with write barrier
2130 // newlen = len + 3 // recalculate to avoid a spill
2132 // // with write barriers, if needed:
2134 // *(ptr+len+1) = e2
2135 // *(ptr+len+2) = e3
2141 sn := n.List.First() // the slice node is the first in the list
2143 var slice, addr *ssa.Value
2145 addr = s.addr(sn, false)
2146 slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
2151 // Allocate new blocks
2152 grow := s.f.NewBlock(ssa.BlockPlain)
2153 assign := s.f.NewBlock(ssa.BlockPlain)
2155 // Decide if we need to grow
2156 nargs := int64(n.List.Len() - 1)
2157 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2158 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2159 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2160 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2162 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
2166 s.vars[&newlenVar] = nl
2173 b.Kind = ssa.BlockIf
2174 b.Likely = ssa.BranchUnlikely
2181 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(n.Type.Elem())}, s.sb)
2183 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
2187 // Tell liveness we're about to build a new slice
2188 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, sn, s.mem())
2190 capaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_cap), addr)
2191 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capaddr, r[2], s.mem())
2192 s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
2193 // load the value we just stored to avoid having to spill it
2194 s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
2195 s.vars[&lenVar] = r[1] // avoid a spill in the fast path
2197 s.vars[&ptrVar] = r[0]
2198 s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], r[1], s.constInt(Types[TINT], nargs))
2199 s.vars[&capVar] = r[2]
2205 // assign new elements to slots
2206 s.startBlock(assign)
2209 l = s.variable(&lenVar, Types[TINT]) // generates phi for len
2210 nl = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2211 lenaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_nel), addr)
2212 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenaddr, nl, s.mem())
2216 args := make([]*ssa.Value, 0, nargs)
2217 store := make([]bool, 0, nargs)
2218 for _, n := range n.List.Slice()[1:] {
2219 if canSSAType(n.Type) {
2220 args = append(args, s.expr(n))
2221 store = append(store, true)
2223 args = append(args, s.addr(n, false))
2224 store = append(store, false)
2228 p = s.variable(&ptrVar, pt) // generates phi for ptr
2230 nl = s.variable(&newlenVar, Types[TINT]) // generates phi for nl
2231 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
2233 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
2234 // TODO: just one write barrier call for all of these writes?
2235 // TODO: maybe just one writeBarrier.enabled check?
2236 for i, arg := range args {
2237 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
2239 if haspointers(et) {
2240 s.insertWBstore(et, addr, arg, n.Lineno, 0)
2242 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2245 if haspointers(et) {
2246 s.insertWBmove(et, addr, arg, n.Lineno)
2248 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2253 delete(s.vars, &ptrVar)
2255 delete(s.vars, &lenVar)
2258 delete(s.vars, &newlenVar)
2259 delete(s.vars, &capVar)
2261 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2264 // condBranch evaluates the boolean expression cond and branches to yes
2265 // if cond is true and no if cond is false.
2266 // This function is intended to handle && and || better than just calling
2267 // s.expr(cond) and branching on the result.
2268 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2269 if cond.Op == OANDAND {
2270 mid := s.f.NewBlock(ssa.BlockPlain)
2271 s.stmtList(cond.Ninit)
2272 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2274 s.condBranch(cond.Right, yes, no, likely)
2276 // Note: if likely==1, then both recursive calls pass 1.
2277 // If likely==-1, then we don't have enough information to decide
2278 // whether the first branch is likely or not. So we pass 0 for
2279 // the likeliness of the first branch.
2280 // TODO: have the frontend give us branch prediction hints for
2281 // OANDAND and OOROR nodes (if it ever has such info).
2283 if cond.Op == OOROR {
2284 mid := s.f.NewBlock(ssa.BlockPlain)
2285 s.stmtList(cond.Ninit)
2286 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2288 s.condBranch(cond.Right, yes, no, likely)
2290 // Note: if likely==-1, then both recursive calls pass -1.
2291 // If likely==1, then we don't have enough info to decide
2292 // the likelihood of the first branch.
2294 if cond.Op == ONOT {
2295 s.stmtList(cond.Ninit)
2296 s.condBranch(cond.Left, no, yes, -likely)
2301 b.Kind = ssa.BlockIf
2303 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2311 skipPtr skipMask = 1 << iota
2316 // assign does left = right.
2317 // Right has already been evaluated to ssa, left has not.
2318 // If deref is true, then we do left = *right instead (and right has already been nil-checked).
2319 // If deref is true and right == nil, just do left = 0.
2320 // Include a write barrier if wb is true.
2321 // skip indicates assignments (at the top level) that can be avoided.
2322 func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask) {
2323 if left.Op == ONAME && isblank(left) {
2330 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2332 if left.Op == ODOT {
2333 // We're assigning to a field of an ssa-able value.
2334 // We need to build a new structure with the new value for the
2335 // field we're assigning and the old values for the other fields.
2337 // type T struct {a, b, c int}
2340 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2342 // Grab information about the structure type.
2345 idx := fieldIdx(left)
2347 // Grab old value of structure.
2348 old := s.expr(left.Left)
2350 // Make new structure.
2351 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2353 // Add fields as args.
2354 for i := 0; i < nf; i++ {
2358 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
2362 // Recursively assign the new value we've made to the base of the dot op.
2363 s.assign(left.Left, new, false, false, line, 0)
2364 // TODO: do we need to update named values here?
2367 // Update variable assignment.
2368 s.vars[left] = right
2369 s.addNamedValue(left, right)
2372 // Left is not ssa-able. Compute its address.
2373 addr := s.addr(left, false)
2374 if left.Op == ONAME && skip == 0 {
2375 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2378 // Treat as a mem->mem move.
2380 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2384 s.insertWBmove(t, addr, right, line)
2387 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2390 // Treat as a store.
2392 if skip&skipPtr != 0 {
2393 // Special case: if we don't write back the pointers, don't bother
2394 // doing the write barrier check.
2395 s.storeTypeScalars(t, addr, right, skip)
2398 s.insertWBstore(t, addr, right, line, skip)
2402 if skip&skipPtr == 0 {
2403 s.storeTypePtrs(t, addr, right)
2405 s.storeTypeScalars(t, addr, right, skip)
2408 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
2411 // zeroVal returns the zero value for type t.
2412 func (s *state) zeroVal(t *Type) *ssa.Value {
2417 return s.constInt8(t, 0)
2419 return s.constInt16(t, 0)
2421 return s.constInt32(t, 0)
2423 return s.constInt64(t, 0)
2425 s.Fatalf("bad sized integer type %s", t)
2430 return s.constFloat32(t, 0)
2432 return s.constFloat64(t, 0)
2434 s.Fatalf("bad sized float type %s", t)
2439 z := s.constFloat32(Types[TFLOAT32], 0)
2440 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2442 z := s.constFloat64(Types[TFLOAT64], 0)
2443 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2445 s.Fatalf("bad sized complex type %s", t)
2449 return s.constEmptyString(t)
2450 case t.IsPtrShaped():
2451 return s.constNil(t)
2453 return s.constBool(false)
2454 case t.IsInterface():
2455 return s.constInterface(t)
2457 return s.constSlice(t)
2460 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
2461 for i := 0; i < n; i++ {
2462 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2466 s.Unimplementedf("zero for type %v not implemented", t)
2473 callNormal callKind = iota
2478 // isSSAIntrinsic1 returns true if n is a call to a recognized 1-arg intrinsic
2479 // that can be handled by the SSA backend.
2480 // SSA uses this, but so does the front end to see if should not
2481 // inline a function because it is a candidate for intrinsic
2483 func isSSAIntrinsic1(s *Sym) bool {
2484 // The test below is not quite accurate -- in the event that
2485 // a function is disabled on a per-function basis, for example
2486 // because of hash-keyed binary failure search, SSA might be
2487 // disabled for that function but it would not be noted here,
2488 // and thus an inlining would not occur (in practice, inlining
2489 // so far has only been noticed for Bswap32 and the 16-bit count
2490 // leading/trailing instructions, but heuristics might change
2491 // in the future or on different architectures).
2492 if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
2495 if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
2498 "Ctz64", "Ctz32", "Ctz16",
2499 "Bswap64", "Bswap32":
2506 func isIntrinsicCall1(n *Node) bool {
2507 if n == nil || n.Left == nil {
2510 return isSSAIntrinsic1(n.Left.Sym)
2513 // intrinsicFirstArg extracts arg from n.List and eval
2514 func (s *state) intrinsicFirstArg(n *Node) *ssa.Value {
2522 // intrinsicCall1 converts a call to a recognized 1-arg intrinsic
2523 // into the intrinsic
2524 func (s *state) intrinsicCall1(n *Node) *ssa.Value {
2525 var result *ssa.Value
2526 switch n.Left.Sym.Name {
2528 result = s.newValue1(ssa.OpCtz64, Types[TUINT64], s.intrinsicFirstArg(n))
2530 result = s.newValue1(ssa.OpCtz32, Types[TUINT32], s.intrinsicFirstArg(n))
2532 result = s.newValue1(ssa.OpCtz16, Types[TUINT16], s.intrinsicFirstArg(n))
2534 result = s.newValue1(ssa.OpBswap64, Types[TUINT64], s.intrinsicFirstArg(n))
2536 result = s.newValue1(ssa.OpBswap32, Types[TUINT32], s.intrinsicFirstArg(n))
2539 Fatalf("Unknown special call: %v", n.Left.Sym)
2541 if ssa.IntrinsicsDebug > 0 {
2542 Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, result.LongString())
2547 // Calls the function n using the specified call type.
2548 // Returns the address of the return value (or nil if none).
2549 func (s *state) call(n *Node, k callKind) *ssa.Value {
2550 var sym *Sym // target symbol (if static)
2551 var closure *ssa.Value // ptr to closure to run (if dynamic)
2552 var codeptr *ssa.Value // ptr to target code (if dynamic)
2553 var rcvr *ssa.Value // receiver to set
2557 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2561 closure = s.expr(fn)
2563 if fn.Op != ODOTMETH {
2564 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2566 if k == callNormal {
2570 n2 := newname(fn.Sym)
2572 n2.Lineno = fn.Lineno
2573 closure = s.expr(n2)
2574 // Note: receiver is already assigned in n.List, so we don't
2575 // want to set it here.
2577 if fn.Op != ODOTINTER {
2578 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", fn.Op)
2580 i := s.expr(fn.Left)
2581 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2582 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2583 itab = s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), itabidx, itab)
2584 if k == callNormal {
2585 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2589 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2592 stksize := fn.Type.ArgWidth() // includes receiver
2594 // Run all argument assignments. The arg slots have already
2595 // been offset by the appropriate amount (+2*widthptr for go/defer,
2596 // +widthptr for interface calls).
2597 // For OCALLMETH, the receiver is set in these statements.
2600 // Set receiver (for interface calls)
2602 argStart := Ctxt.FixedFrameSize()
2603 if k != callNormal {
2604 argStart += int64(2 * Widthptr)
2606 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), argStart, s.sp)
2607 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
2611 if k != callNormal {
2612 // Write argsize and closure (args to Newproc/Deferproc).
2613 argStart := Ctxt.FixedFrameSize()
2614 argsize := s.constInt32(Types[TUINT32], int32(stksize))
2615 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT32]), argStart, s.sp)
2616 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, addr, argsize, s.mem())
2617 addr = s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), argStart+int64(Widthptr), s.sp)
2618 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
2619 stksize += 2 * int64(Widthptr)
2623 bNext := s.f.NewBlock(ssa.BlockPlain)
2626 case k == callDefer:
2627 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2629 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2630 case closure != nil:
2631 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2632 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2633 case codeptr != nil:
2634 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2636 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2638 Fatalf("bad call type %s %v", n.Op, n)
2640 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2642 // Finish call block
2643 s.vars[&memVar] = call
2645 b.Kind = ssa.BlockCall
2649 // Add recover edge to exit code.
2650 b.Kind = ssa.BlockDefer
2651 r := s.f.NewBlock(ssa.BlockPlain)
2655 b.Likely = ssa.BranchLikely
2658 // Start exit block, find address of result.
2660 // Keep input pointer args live across calls. This is a bandaid until 1.8.
2661 for _, n := range s.ptrargs {
2662 s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
2664 res := n.Left.Type.Results()
2665 if res.NumFields() == 0 || k != callNormal {
2666 // call has no return value. Continue with the next statement.
2670 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
2673 // etypesign returns the signed-ness of e, for integer/pointer etypes.
2674 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
2675 func etypesign(e EType) int8 {
2677 case TINT8, TINT16, TINT32, TINT64, TINT:
2679 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2685 // lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2686 // This improves the effectiveness of cse by using the same Aux values for the
2688 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2691 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2692 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2693 // these are the only valid types
2696 if lsym, ok := s.varsyms[n]; ok {
2704 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
2705 // The value that the returned Value represents is guaranteed to be non-nil.
2706 // If bounded is true then this address does not require a nil check for its operand
2707 // even if that would otherwise be implied.
2708 func (s *state) addr(n *Node, bounded bool) *ssa.Value {
2715 aux := s.lookupSymbol(n, &ssa.ExternSymbol{Typ: n.Type, Sym: n.Sym})
2716 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
2717 // TODO: Make OpAddr use AuxInt as well as Aux.
2719 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2728 if n.String() == ".fp" {
2729 // Special arg that points to the frame pointer.
2730 // (Used by the race detector, others?)
2731 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2732 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2734 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2737 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
2738 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2739 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
2740 // ensure that we reuse symbols for out parameters so
2741 // that cse works on their addresses
2742 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2743 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2745 s.Unimplementedf("variable address class %v not implemented", classnames[n.Class])
2749 // indirect off a register
2750 // used for storing/loading arguments/returns to/from callees
2751 if int(n.Reg) != Thearch.REGSP {
2752 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2755 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
2757 if n.Left.Type.IsSlice() {
2759 i := s.expr(n.Right)
2760 i = s.extendIndex(i, Panicindex)
2761 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
2763 s.boundsCheck(i, len)
2765 p := s.newValue1(ssa.OpSlicePtr, t, a)
2766 return s.newValue2(ssa.OpPtrIndex, t, p, i)
2768 a := s.addr(n.Left, bounded)
2769 i := s.expr(n.Right)
2770 i = s.extendIndex(i, Panicindex)
2771 len := s.constInt(Types[TINT], n.Left.Type.NumElem())
2773 s.boundsCheck(i, len)
2775 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
2778 return s.exprPtr(n.Left, bounded, n.Lineno)
2780 p := s.addr(n.Left, bounded)
2781 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
2783 p := s.exprPtr(n.Left, bounded, n.Lineno)
2784 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
2786 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
2787 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
2789 addr := s.addr(n.Left, bounded)
2790 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
2791 case OCALLFUNC, OCALLINTER, OCALLMETH:
2792 return s.call(n, callNormal)
2795 s.Unimplementedf("unhandled addr %v", n.Op)
2800 // canSSA reports whether n is SSA-able.
2801 // n must be an ONAME (or an ODOT sequence with an ONAME base).
2802 func (s *state) canSSA(n *Node) bool {
2803 if Debug['N'] != 0 {
2815 if n.isParamHeapCopy() {
2818 if n.Class == PAUTOHEAP {
2819 Fatalf("canSSA of PAUTOHEAP %v", n)
2826 // TODO: handle this case? Named return values must be
2827 // in memory so that the deferred function can see them.
2828 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
2831 if s.cgoUnsafeArgs {
2832 // Cgo effectively takes the address of all result args,
2833 // but the compiler can't see that.
2837 if n.Class == PPARAM && n.String() == ".this" {
2838 // wrappers generated by genwrapper need to update
2839 // the .this pointer in place.
2840 // TODO: treat as a PPARMOUT?
2843 return canSSAType(n.Type)
2844 // TODO: try to make more variables SSAable?
2847 // canSSA reports whether variables of type t are SSA-able.
2848 func canSSAType(t *Type) bool {
2850 if t.Width > int64(4*Widthptr) {
2851 // 4*Widthptr is an arbitrary constant. We want it
2852 // to be at least 3*Widthptr so slices can be registerized.
2853 // Too big and we'll introduce too much register pressure.
2858 // We can't do arrays because dynamic indexing is
2859 // not supported on SSA variables.
2860 // TODO: maybe allow if length is <=1? All indexes
2861 // are constant? Might be good for the arrays
2862 // introduced by the compiler for variadic functions.
2865 if t.NumFields() > ssa.MaxStruct {
2868 for _, t1 := range t.Fields().Slice() {
2869 if !canSSAType(t1.Type) {
2879 // exprPtr evaluates n to a pointer and nil-checks it.
2880 func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
2882 if bounded || n.NonNil {
2883 if s.f.Config.Debug_checknil() && lineno > 1 {
2884 s.f.Config.Warnl(lineno, "removed nil check")
2892 // nilCheck generates nil pointer checking code.
2893 // Starts a new block on return, unless nil checks are disabled.
2894 // Used only for automatically inserted nil checks,
2895 // not for user code like 'x != nil'.
2896 func (s *state) nilCheck(ptr *ssa.Value) {
2897 if Disable_checknil != 0 {
2900 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
2902 b.Kind = ssa.BlockCheck
2904 bNext := s.f.NewBlock(ssa.BlockPlain)
2909 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2910 // Starts a new block on return.
2911 // idx is already converted to full int width.
2912 func (s *state) boundsCheck(idx, len *ssa.Value) {
2913 if Debug['B'] != 0 {
2918 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
2919 s.check(cmp, Panicindex)
2922 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2923 // Starts a new block on return.
2924 // idx and len are already converted to full int width.
2925 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2926 if Debug['B'] != 0 {
2931 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
2932 s.check(cmp, panicslice)
2935 // If cmp (a bool) is false, panic using the given function.
2936 func (s *state) check(cmp *ssa.Value, fn *Node) {
2938 b.Kind = ssa.BlockIf
2940 b.Likely = ssa.BranchLikely
2941 bNext := s.f.NewBlock(ssa.BlockPlain)
2942 line := s.peekLine()
2943 bPanic := s.panics[funcLine{fn, line}]
2945 bPanic = s.f.NewBlock(ssa.BlockPlain)
2946 s.panics[funcLine{fn, line}] = bPanic
2947 s.startBlock(bPanic)
2948 // The panic call takes/returns memory to ensure that the right
2949 // memory state is observed if the panic happens.
2950 s.rtcall(fn, false, nil)
2957 // rtcall issues a call to the given runtime function fn with the listed args.
2958 // Returns a slice of results of the given result types.
2959 // The call is added to the end of the current block.
2960 // If returns is false, the block is marked as an exit block.
2961 // If returns is true, the block is marked as a call block. A new block
2962 // is started to load the return values.
2963 func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2964 // Write args to the stack
2965 off := Ctxt.FixedFrameSize()
2966 for _, arg := range args {
2968 off = Rnd(off, t.Alignment())
2971 ptr = s.newValue1I(ssa.OpOffPtr, t.PtrTo(), off, s.sp)
2974 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2977 off = Rnd(off, int64(Widthptr))
2980 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2981 s.vars[&memVar] = call
2986 b.Kind = ssa.BlockExit
2989 if len(results) > 0 {
2990 Fatalf("panic call can't have results")
2994 b.Kind = ssa.BlockCall
2996 bNext := s.f.NewBlock(ssa.BlockPlain)
3000 // Keep input pointer args live across calls. This is a bandaid until 1.8.
3001 for _, n := range s.ptrargs {
3002 s.vars[&memVar] = s.newValue2(ssa.OpKeepAlive, ssa.TypeMem, s.variable(n, n.Type), s.mem())
3006 res := make([]*ssa.Value, len(results))
3007 for i, t := range results {
3008 off = Rnd(off, t.Alignment())
3011 ptr = s.newValue1I(ssa.OpOffPtr, Ptrto(t), off, s.sp)
3013 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
3016 off = Rnd(off, int64(Widthptr))
3018 // Remember how much callee stack space we needed.
3024 // insertWBmove inserts the assignment *left = *right including a write barrier.
3025 // t is the type being assigned.
3026 func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
3027 // if writeBarrier.enabled {
3028 // typedmemmove(&t, left, right)
3034 s.Fatalf("write barrier prohibited")
3036 if s.WBLineno == 0 {
3037 s.WBLineno = left.Line
3039 bThen := s.f.NewBlock(ssa.BlockPlain)
3040 bElse := s.f.NewBlock(ssa.BlockPlain)
3041 bEnd := s.f.NewBlock(ssa.BlockPlain)
3043 aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
3044 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
3045 // Load word, test word, avoiding partial register write from load byte.
3046 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
3047 flag = s.newValue2(ssa.OpNeq32, Types[TBOOL], flag, s.constInt32(Types[TUINT32], 0))
3049 b.Kind = ssa.BlockIf
3050 b.Likely = ssa.BranchUnlikely
3056 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Typ: Types[TUINTPTR], Sym: typenamesym(t)}, s.sb)
3057 s.rtcall(typedmemmove, true, nil, taddr, left, right)
3058 s.endBlock().AddEdgeTo(bEnd)
3061 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
3062 s.endBlock().AddEdgeTo(bEnd)
3067 Warnl(line, "write barrier")
3071 // insertWBstore inserts the assignment *left = right including a write barrier.
3072 // t is the type being assigned.
3073 func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) {
3074 // store scalar fields
3075 // if writeBarrier.enabled {
3076 // writebarrierptr for pointer fields
3078 // store pointer fields
3082 s.Fatalf("write barrier prohibited")
3084 if s.WBLineno == 0 {
3085 s.WBLineno = left.Line
3087 s.storeTypeScalars(t, left, right, skip)
3089 bThen := s.f.NewBlock(ssa.BlockPlain)
3090 bElse := s.f.NewBlock(ssa.BlockPlain)
3091 bEnd := s.f.NewBlock(ssa.BlockPlain)
3093 aux := &ssa.ExternSymbol{Typ: Types[TBOOL], Sym: syslook("writeBarrier").Sym}
3094 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
3095 // Load word, test word, avoiding partial register write from load byte.
3096 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
3097 flag = s.newValue2(ssa.OpNeq32, Types[TBOOL], flag, s.constInt32(Types[TUINT32], 0))
3099 b.Kind = ssa.BlockIf
3100 b.Likely = ssa.BranchUnlikely
3105 // Issue write barriers for pointer writes.
3107 s.storeTypePtrsWB(t, left, right)
3108 s.endBlock().AddEdgeTo(bEnd)
3110 // Issue regular stores for pointer writes.
3112 s.storeTypePtrs(t, left, right)
3113 s.endBlock().AddEdgeTo(bEnd)
3118 Warnl(line, "write barrier")
3122 // do *left = right for all scalar (non-pointer) parts of t.
3123 func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask) {
3125 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
3126 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
3127 case t.IsPtrShaped():
3128 // no scalar fields.
3130 if skip&skipLen != 0 {
3133 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
3134 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3135 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3137 if skip&skipLen == 0 {
3138 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
3139 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3140 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3142 if skip&skipCap == 0 {
3143 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
3144 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
3145 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
3147 case t.IsInterface():
3148 // itab field doesn't need a write barrier (even though it is a pointer).
3149 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
3150 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
3153 for i := 0; i < n; i++ {
3154 ft := t.FieldType(i)
3155 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
3156 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
3157 s.storeTypeScalars(ft.(*Type), addr, val, 0)
3160 s.Fatalf("bad write barrier type %s", t)
3164 // do *left = right for all pointer parts of t.
3165 func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
3167 case t.IsPtrShaped():
3168 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
3170 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3171 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3173 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3174 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3175 case t.IsInterface():
3176 // itab field is treated as a scalar.
3177 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3178 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3179 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
3182 for i := 0; i < n; i++ {
3183 ft := t.FieldType(i)
3184 if !haspointers(ft.(*Type)) {
3187 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
3188 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
3189 s.storeTypePtrs(ft.(*Type), addr, val)
3192 s.Fatalf("bad write barrier type %s", t)
3196 // do *left = right with a write barrier for all pointer parts of t.
3197 func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
3199 case t.IsPtrShaped():
3200 s.rtcall(writebarrierptr, true, nil, left, right)
3202 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3203 s.rtcall(writebarrierptr, true, nil, left, ptr)
3205 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3206 s.rtcall(writebarrierptr, true, nil, left, ptr)
3207 case t.IsInterface():
3208 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3209 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3210 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
3213 for i := 0; i < n; i++ {
3214 ft := t.FieldType(i)
3215 if !haspointers(ft.(*Type)) {
3218 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
3219 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
3220 s.storeTypePtrsWB(ft.(*Type), addr, val)
3223 s.Fatalf("bad write barrier type %s", t)
3227 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
3228 // i,j,k may be nil, in which case they are set to their default value.
3229 // t is a slice, ptr to array, or string type.
3230 func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
3236 zero := s.constInt(Types[TINT], 0)
3240 ptrtype = Ptrto(elemtype)
3241 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
3242 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
3243 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
3245 elemtype = Types[TUINT8]
3246 ptrtype = Ptrto(elemtype)
3247 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
3248 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
3251 if !t.Elem().IsArray() {
3252 s.Fatalf("bad ptr to array in slice %v\n", t)
3254 elemtype = t.Elem().Elem()
3255 ptrtype = Ptrto(elemtype)
3258 len = s.constInt(Types[TINT], t.Elem().NumElem())
3261 s.Fatalf("bad type in slice %v\n", t)
3264 // Set default values
3275 // Panic if slice indices are not in bounds.
3276 s.sliceBoundsCheck(i, j)
3278 s.sliceBoundsCheck(j, k)
3281 s.sliceBoundsCheck(k, cap)
3284 // Generate the following code assuming that indexes are in bounds.
3285 // The conditional is to make sure that we don't generate a slice
3286 // that points to the next object in memory.
3289 // delta = i*elemsize
3294 // result = (SliceMake rptr rlen rcap)
3295 subOp := s.ssaOp(OSUB, Types[TINT])
3296 eqOp := s.ssaOp(OEQ, Types[TINT])
3297 mulOp := s.ssaOp(OMUL, Types[TINT])
3298 rlen := s.newValue2(subOp, Types[TINT], j, i)
3302 // Capacity of the result is unimportant. However, we use
3303 // rcap to test if we've generated a zero-length slice.
3304 // Use length of strings for that.
3309 rcap = s.newValue2(subOp, Types[TINT], k, i)
3312 // delta = # of elements to offset pointer by.
3313 s.vars[&deltaVar] = i
3315 // Generate code to set delta=0 if the resulting capacity is zero.
3316 if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
3317 (i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
3318 cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
3321 b.Kind = ssa.BlockIf
3322 b.Likely = ssa.BranchUnlikely
3325 // Generate block which zeros the delta variable.
3326 nz := s.f.NewBlock(ssa.BlockPlain)
3329 s.vars[&deltaVar] = zero
3333 merge := s.f.NewBlock(ssa.BlockPlain)
3338 // TODO: use conditional moves somehow?
3341 // Compute rptr = ptr + delta * elemsize
3342 rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
3343 delete(s.vars, &deltaVar)
3344 return rptr, rlen, rcap
3347 type u2fcvtTab struct {
3348 geq, cvt2F, and, rsh, or, add ssa.Op
3349 one func(*state, ssa.Type, int64) *ssa.Value
3352 var u64_f64 u2fcvtTab = u2fcvtTab{
3354 cvt2F: ssa.OpCvt64to64F,
3356 rsh: ssa.OpRsh64Ux64,
3359 one: (*state).constInt64,
3362 var u64_f32 u2fcvtTab = u2fcvtTab{
3364 cvt2F: ssa.OpCvt64to32F,
3366 rsh: ssa.OpRsh64Ux64,
3369 one: (*state).constInt64,
3372 // Excess generality on a machine with 64-bit integer registers.
3373 // Not used on AMD64.
3374 var u32_f32 u2fcvtTab = u2fcvtTab{
3376 cvt2F: ssa.OpCvt32to32F,
3378 rsh: ssa.OpRsh32Ux32,
3381 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3382 return s.constInt32(t, int32(x))
3386 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3387 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3390 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3391 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3394 func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3396 // result = (floatY) x
3398 // y = uintX(x) ; y = x & 1
3399 // z = uintX(x) ; z = z >> 1
3402 // result = floatY(z)
3403 // result = result + result
3406 // Code borrowed from old code generator.
3407 // What's going on: large 64-bit "unsigned" looks like
3408 // negative number to hardware's integer-to-float
3409 // conversion. However, because the mantissa is only
3410 // 63 bits, we don't need the LSB, so instead we do an
3411 // unsigned right shift (divide by two), convert, and
3412 // double. However, before we do that, we need to be
3413 // sure that we do not lose a "1" if that made the
3414 // difference in the resulting rounding. Therefore, we
3415 // preserve it, and OR (not ADD) it back in. The case
3416 // that matters is when the eleven discarded bits are
3417 // equal to 10000000001; that rounds up, and the 1 cannot
3418 // be lost else it would round down if the LSB of the
3419 // candidate mantissa is 0.
3420 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3422 b.Kind = ssa.BlockIf
3424 b.Likely = ssa.BranchLikely
3426 bThen := s.f.NewBlock(ssa.BlockPlain)
3427 bElse := s.f.NewBlock(ssa.BlockPlain)
3428 bAfter := s.f.NewBlock(ssa.BlockPlain)
3432 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3435 bThen.AddEdgeTo(bAfter)
3439 one := cvttab.one(s, ft, 1)
3440 y := s.newValue2(cvttab.and, ft, x, one)
3441 z := s.newValue2(cvttab.rsh, ft, x, one)
3442 z = s.newValue2(cvttab.or, ft, z, y)
3443 a := s.newValue1(cvttab.cvt2F, tt, z)
3444 a1 := s.newValue2(cvttab.add, tt, a, a)
3447 bElse.AddEdgeTo(bAfter)
3449 s.startBlock(bAfter)
3450 return s.variable(n, n.Type)
3453 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3454 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3455 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3456 s.Fatalf("node must be a map or a channel")
3462 // return *((*int)n)
3464 // return *(((*int)n)+1)
3467 nilValue := s.constNil(Types[TUINTPTR])
3468 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
3470 b.Kind = ssa.BlockIf
3472 b.Likely = ssa.BranchUnlikely
3474 bThen := s.f.NewBlock(ssa.BlockPlain)
3475 bElse := s.f.NewBlock(ssa.BlockPlain)
3476 bAfter := s.f.NewBlock(ssa.BlockPlain)
3478 // length/capacity of a nil map/chan is zero
3481 s.vars[n] = s.zeroVal(lenType)
3483 bThen.AddEdgeTo(bAfter)
3488 // length is stored in the first word for map/chan
3489 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3490 } else if n.Op == OCAP {
3491 // capacity is stored in the second word for chan
3492 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3493 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3495 s.Fatalf("op must be OLEN or OCAP")
3498 bElse.AddEdgeTo(bAfter)
3500 s.startBlock(bAfter)
3501 return s.variable(n, lenType)
3504 type f2uCvtTab struct {
3505 ltf, cvt2U, subf ssa.Op
3506 value func(*state, ssa.Type, float64) *ssa.Value
3509 var f32_u64 f2uCvtTab = f2uCvtTab{
3511 cvt2U: ssa.OpCvt32Fto64,
3513 value: (*state).constFloat32,
3516 var f64_u64 f2uCvtTab = f2uCvtTab{
3518 cvt2U: ssa.OpCvt64Fto64,
3520 value: (*state).constFloat64,
3523 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3524 return s.floatToUint(&f32_u64, n, x, ft, tt)
3526 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3527 return s.floatToUint(&f64_u64, n, x, ft, tt)
3530 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3531 // if x < 9223372036854775808.0 {
3532 // result = uintY(x)
3534 // y = x - 9223372036854775808.0
3536 // result = z | -9223372036854775808
3538 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3539 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3541 b.Kind = ssa.BlockIf
3543 b.Likely = ssa.BranchLikely
3545 bThen := s.f.NewBlock(ssa.BlockPlain)
3546 bElse := s.f.NewBlock(ssa.BlockPlain)
3547 bAfter := s.f.NewBlock(ssa.BlockPlain)
3551 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3554 bThen.AddEdgeTo(bAfter)
3558 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3559 y = s.newValue1(cvttab.cvt2U, tt, y)
3560 z := s.constInt64(tt, -9223372036854775808)
3561 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3564 bElse.AddEdgeTo(bAfter)
3566 s.startBlock(bAfter)
3567 return s.variable(n, n.Type)
3570 // ifaceType returns the value for the word containing the type.
3571 // n is the node for the interface expression.
3572 // v is the corresponding value.
3573 func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3574 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3576 if n.Type.IsEmptyInterface() {
3577 // Have *eface. The type is the first word in the struct.
3578 return s.newValue1(ssa.OpITab, byteptr, v)
3582 // The first word in the struct is the *itab.
3583 // If the *itab is nil, return 0.
3584 // Otherwise, the second word in the *itab is the type.
3586 tab := s.newValue1(ssa.OpITab, byteptr, v)
3587 s.vars[&typVar] = tab
3588 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
3590 b.Kind = ssa.BlockIf
3591 b.SetControl(isnonnil)
3592 b.Likely = ssa.BranchLikely
3594 bLoad := s.f.NewBlock(ssa.BlockPlain)
3595 bEnd := s.f.NewBlock(ssa.BlockPlain)
3599 bLoad.AddEdgeTo(bEnd)
3602 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3603 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3607 typ := s.variable(&typVar, byteptr)
3608 delete(s.vars, &typVar)
3612 // dottype generates SSA for a type assertion node.
3613 // commaok indicates whether to panic or return a bool.
3614 // If commaok is false, resok will be nil.
3615 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3616 iface := s.expr(n.Left)
3617 typ := s.ifaceType(n.Left, iface) // actual concrete type
3618 target := s.expr(typename(n.Type)) // target type
3619 if !isdirectiface(n.Type) {
3620 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3621 Fatalf("dottype needs a direct iface type %s", n.Type)
3624 if Debug_typeassert > 0 {
3625 Warnl(n.Lineno, "type assertion inlined")
3628 // TODO: If we have a nonempty interface and its itab field is nil,
3629 // then this test is redundant and ifaceType should just branch directly to bFail.
3630 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3632 b.Kind = ssa.BlockIf
3634 b.Likely = ssa.BranchLikely
3636 byteptr := Ptrto(Types[TUINT8])
3638 bOk := s.f.NewBlock(ssa.BlockPlain)
3639 bFail := s.f.NewBlock(ssa.BlockPlain)
3644 // on failure, panic by calling panicdottype
3646 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{Typ: byteptr, Sym: typenamesym(n.Left.Type)}, s.sb)
3647 s.rtcall(panicdottype, false, nil, typ, target, taddr)
3649 // on success, return idata field
3651 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3654 // commaok is the more complicated case because we have
3655 // a control flow merge point.
3656 bEnd := s.f.NewBlock(ssa.BlockPlain)
3658 // type assertion succeeded
3660 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3661 s.vars[&okVar] = s.constBool(true)
3665 // type assertion failed
3667 s.vars[&idataVar] = s.constNil(byteptr)
3668 s.vars[&okVar] = s.constBool(false)
3670 bFail.AddEdgeTo(bEnd)
3674 res = s.variable(&idataVar, byteptr)
3675 resok = s.variable(&okVar, Types[TBOOL])
3676 delete(s.vars, &idataVar)
3677 delete(s.vars, &okVar)
3681 // checkgoto checks that a goto from from to to does not
3682 // jump into a block or jump over variable declarations.
3683 // It is a copy of checkgoto in the pre-SSA backend,
3684 // modified only for line number handling.
3685 // TODO: document how this works and why it is designed the way it is.
3686 func (s *state) checkgoto(from *Node, to *Node) {
3687 if from.Sym == to.Sym {
3692 for fs := from.Sym; fs != nil; fs = fs.Link {
3696 for fs := to.Sym; fs != nil; fs = fs.Link {
3700 for ; nf > nt; nf-- {
3704 // decide what to complain about.
3705 // prefer to complain about 'into block' over declarations,
3706 // so scan backward to find most recent block or else dcl.
3711 for ; nt > nf; nt-- {
3730 lno := from.Left.Lineno
3732 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
3734 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
3739 // variable returns the value of a variable at the current location.
3740 func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
3743 v = s.newValue0A(ssa.OpFwdRef, t, name)
3744 s.fwdRefs = append(s.fwdRefs, v)
3746 s.addNamedValue(name, v)
3751 func (s *state) mem() *ssa.Value {
3752 return s.variable(&memVar, ssa.TypeMem)
3755 func (s *state) linkForwardReferences(dm *sparseDefState) {
3757 // Build SSA graph. Each variable on its first use in a basic block
3758 // leaves a FwdRef in that block representing the incoming value
3759 // of that variable. This function links that ref up with possible definitions,
3760 // inserting Phi values as needed. This is essentially the algorithm
3761 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3762 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3764 // - We use FwdRef nodes to postpone phi building until the CFG is
3765 // completely built. That way we can avoid the notion of "sealed"
3767 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3768 for len(s.fwdRefs) > 0 {
3769 v := s.fwdRefs[len(s.fwdRefs)-1]
3770 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3771 s.resolveFwdRef(v, dm)
3775 // resolveFwdRef modifies v to be the variable's value at the start of its block.
3776 // v must be a FwdRef op.
3777 func (s *state) resolveFwdRef(v *ssa.Value, dm *sparseDefState) {
3779 name := v.Aux.(*Node)
3782 // Live variable at start of function.
3784 if strings.HasPrefix(name.Sym.Name, "autotmp_") {
3785 // It's likely that this is an uninitialized variable in the entry block.
3786 s.Fatalf("Treating auto as if it were arg, func %s, node %v, value %v", b.Func.Name, name, v)
3792 // Not SSAable. Load it.
3793 addr := s.decladdrs[name]
3795 // TODO: closure args reach here.
3796 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
3798 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3799 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3802 v.AddArgs(addr, s.startmem)
3805 if len(b.Preds) == 0 {
3806 // This block is dead; we have no predecessors and we're not the entry block.
3807 // It doesn't matter what we use here as long as it is well-formed.
3808 v.Op = ssa.OpUnknown
3811 // Find variable value on each predecessor.
3812 var argstore [4]*ssa.Value
3813 args := argstore[:0]
3814 for _, e := range b.Preds {
3816 p = dm.FindBetterDefiningBlock(name, p) // try sparse improvement on p
3817 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
3820 // Decide if we need a phi or not. We need a phi if there
3821 // are two different args (which are both not v).
3823 for _, a := range args {
3825 continue // self-reference
3828 continue // already have this witness
3831 // two witnesses, need a phi value
3836 w = a // save witness
3839 s.Fatalf("no witness for reachable phi %s", v)
3841 // One witness. Make v a copy of w.
3846 // lookupVarOutgoing finds the variable's value at the end of block b.
3847 func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
3849 if v, ok := s.defvars[b.ID][name]; ok {
3852 // The variable is not defined by b and we haven't looked it up yet.
3853 // If b has exactly one predecessor, loop to look it up there.
3854 // Otherwise, give up and insert a new FwdRef and resolve it later.
3855 if len(b.Preds) != 1 {
3858 b = b.Preds[0].Block()
3860 // Generate a FwdRef for the variable and return that.
3861 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3862 s.fwdRefs = append(s.fwdRefs, v)
3863 s.defvars[b.ID][name] = v
3864 s.addNamedValue(name, v)
3868 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3869 if n.Class == Pxxx {
3870 // Don't track our dummy nodes (&memVar etc.).
3873 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3874 // Don't track autotmp_ variables.
3877 if n.Class == PPARAMOUT {
3878 // Don't track named output values. This prevents return values
3879 // from being assigned too early. See #14591 and #14762. TODO: allow this.
3882 if n.Class == PAUTO && n.Xoffset != 0 {
3883 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3885 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3886 values, ok := s.f.NamedValues[loc]
3888 s.f.Names = append(s.f.Names, loc)
3890 s.f.NamedValues[loc] = append(values, v)
3893 // Branch is an unresolved branch.
3894 type Branch struct {
3895 P *obj.Prog // branch instruction
3896 B *ssa.Block // target
3899 // SSAGenState contains state needed during Prog generation.
3900 type SSAGenState struct {
3901 // Branches remembers all the branch instructions we've seen
3902 // and where they would like to go.
3905 // bstart remembers where each block starts (indexed by block ID)
3909 // Pc returns the current Prog.
3910 func (s *SSAGenState) Pc() *obj.Prog {
3914 // SetLineno sets the current source line number.
3915 func (s *SSAGenState) SetLineno(l int32) {
3919 // genssa appends entries to ptxt for each instruction in f.
3920 // gcargs and gclocals are filled in with pointer maps for the frame.
3921 func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3924 e := f.Config.Frontend().(*ssaExport)
3925 // We're about to emit a bunch of Progs.
3926 // Since the only way to get here is to explicitly request it,
3927 // just fail on unimplemented instead of trying to unwind our mess.
3928 e.mustImplement = true
3930 // Remember where each block starts.
3931 s.bstart = make([]*obj.Prog, f.NumBlocks())
3933 var valueProgs map[*obj.Prog]*ssa.Value
3934 var blockProgs map[*obj.Prog]*ssa.Block
3935 var logProgs = e.log
3937 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3938 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3939 f.Logf("genssa %s\n", f.Name)
3940 blockProgs[Pc] = f.Blocks[0]
3943 // Emit basic blocks
3944 for i, b := range f.Blocks {
3946 // Emit values in block
3947 Thearch.SSAMarkMoves(&s, b)
3948 for _, v := range b.Values {
3950 Thearch.SSAGenValue(&s, v)
3952 for ; x != Pc; x = x.Link {
3957 // Emit control flow instructions for block
3959 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
3960 // If -N, leave next==nil so every block with successors
3961 // ends in a JMP (except call blocks - plive doesn't like
3962 // select{send,recv} followed by a JMP call). Helps keep
3963 // line numbers for otherwise empty blocks.
3964 next = f.Blocks[i+1]
3967 Thearch.SSAGenBlock(&s, b, next)
3969 for ; x != Pc; x = x.Link {
3976 for _, br := range s.Branches {
3977 br.P.To.Val = s.bstart[br.B.ID]
3981 for p := ptxt; p != nil; p = p.Link {
3983 if v, ok := valueProgs[p]; ok {
3985 } else if b, ok := blockProgs[p]; ok {
3988 s = " " // most value and branch strings are 2-3 characters long
3990 f.Logf("%s\t%s\n", s, p)
3992 if f.Config.HTML != nil {
3993 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3994 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3995 var buf bytes.Buffer
3996 buf.WriteString("<code>")
3997 buf.WriteString("<dl class=\"ssa-gen\">")
3998 for p := ptxt; p != nil; p = p.Link {
3999 buf.WriteString("<dt class=\"ssa-prog-src\">")
4000 if v, ok := valueProgs[p]; ok {
4001 buf.WriteString(v.HTML())
4002 } else if b, ok := blockProgs[p]; ok {
4003 buf.WriteString(b.HTML())
4005 buf.WriteString("</dt>")
4006 buf.WriteString("<dd class=\"ssa-prog\">")
4007 buf.WriteString(html.EscapeString(p.String()))
4008 buf.WriteString("</dd>")
4009 buf.WriteString("</li>")
4011 buf.WriteString("</dl>")
4012 buf.WriteString("</code>")
4013 f.Config.HTML.WriteColumn("genssa", buf.String())
4014 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
4019 if f.StaticData != nil {
4020 for _, n := range f.StaticData.([]*Node) {
4021 if !gen_as_init(n, false) {
4022 Fatalf("non-static data marked as static: %v\n\n", n)
4027 // Allocate stack frame
4030 // Generate gc bitmaps.
4031 liveness(Curfn, ptxt, gcargs, gclocals)
4033 // Add frame prologue. Zero ambiguously live variables.
4034 Thearch.Defframe(ptxt)
4035 if Debug['f'] != 0 {
4039 // Remove leftover instrumentation from the instruction stream.
4042 f.Config.HTML.Close()
4045 // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4046 func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4048 // TODO: use zero register on archs that support it.
4049 p.From.Type = obj.TYPE_CONST
4051 p.To.Type = obj.TYPE_MEM
4053 p.To.Offset = offset
4055 nleft = nbytes - width
4056 return nleft, offset
4059 type FloatingEQNEJump struct {
4064 func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
4065 p := Prog(jumps.Jump)
4066 p.To.Type = obj.TYPE_BRANCH
4068 branches = append(branches, Branch{p, b.Succs[to].Block()})
4072 // liblink reorders the instruction stream as it sees fit.
4073 // Pass along what we know so liblink can make use of it.
4074 // TODO: Once we've fully switched to SSA,
4075 // make liblink leave our output alone.
4077 case ssa.BranchUnlikely:
4078 p.From.Type = obj.TYPE_CONST
4080 case ssa.BranchLikely:
4081 p.From.Type = obj.TYPE_CONST
4087 func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
4090 case b.Succs[0].Block():
4091 s.Branches = oneFPJump(b, &jumps[0][0], likely, s.Branches)
4092 s.Branches = oneFPJump(b, &jumps[0][1], likely, s.Branches)
4093 case b.Succs[1].Block():
4094 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
4095 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
4097 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
4098 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
4100 q.To.Type = obj.TYPE_BRANCH
4101 s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()})
4105 // AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4106 func AddAux(a *obj.Addr, v *ssa.Value) {
4107 AddAux2(a, v, v.AuxInt)
4109 func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
4110 if a.Type != obj.TYPE_MEM && a.Type != obj.TYPE_ADDR {
4111 v.Fatalf("bad AddAux addr %v", a)
4113 // add integer offset
4116 // If no additional symbol offset, we're done.
4120 // Add symbol's offset from its base register.
4121 switch sym := v.Aux.(type) {
4122 case *ssa.ExternSymbol:
4123 a.Name = obj.NAME_EXTERN
4124 switch s := sym.Sym.(type) {
4130 v.Fatalf("ExternSymbol.Sym is %T", s)
4132 case *ssa.ArgSymbol:
4133 n := sym.Node.(*Node)
4134 a.Name = obj.NAME_PARAM
4136 a.Sym = Linksym(n.Orig.Sym)
4137 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
4138 case *ssa.AutoSymbol:
4139 n := sym.Node.(*Node)
4140 a.Name = obj.NAME_AUTO
4142 a.Sym = Linksym(n.Sym)
4144 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4148 // extendIndex extends v to a full int width.
4149 // panic using the given function if v does not fit in an int (only on 32-bit archs).
4150 func (s *state) extendIndex(v *ssa.Value, panicfn *Node) *ssa.Value {
4151 size := v.Type.Size()
4152 if size == s.config.IntSize {
4155 if size > s.config.IntSize {
4156 // truncate 64-bit indexes on 32-bit pointer archs. Test the
4157 // high word and branch to out-of-bounds failure if it is not 0.
4158 if Debug['B'] == 0 {
4159 hi := s.newValue1(ssa.OpInt64Hi, Types[TUINT32], v)
4160 cmp := s.newValue2(ssa.OpEq32, Types[TBOOL], hi, s.constInt32(Types[TUINT32], 0))
4161 s.check(cmp, panicfn)
4163 return s.newValue1(ssa.OpTrunc64to32, Types[TINT], v)
4166 // Extend value to the required size
4168 if v.Type.IsSigned() {
4169 switch 10*size + s.config.IntSize {
4171 op = ssa.OpSignExt8to32
4173 op = ssa.OpSignExt8to64
4175 op = ssa.OpSignExt16to32
4177 op = ssa.OpSignExt16to64
4179 op = ssa.OpSignExt32to64
4181 s.Fatalf("bad signed index extension %s", v.Type)
4184 switch 10*size + s.config.IntSize {
4186 op = ssa.OpZeroExt8to32
4188 op = ssa.OpZeroExt8to64
4190 op = ssa.OpZeroExt16to32
4192 op = ssa.OpZeroExt16to64
4194 op = ssa.OpZeroExt32to64
4196 s.Fatalf("bad unsigned index extension %s", v.Type)
4199 return s.newValue1(op, Types[TINT], v)
4202 // SSARegNum returns the register (in cmd/internal/obj numbering) to
4203 // which v has been allocated. Panics if v is not assigned to a
4205 // TODO: Make this panic again once it stops happening routinely.
4206 func SSARegNum(v *ssa.Value) int16 {
4207 reg := v.Block.Func.RegAlloc[v.ID]
4209 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
4212 return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
4215 // AutoVar returns a *Node and int64 representing the auto variable and offset within it
4216 // where v should be spilled.
4217 func AutoVar(v *ssa.Value) (*Node, int64) {
4218 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
4219 if v.Type.Size() > loc.Type.Size() {
4220 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
4222 return loc.N.(*Node), loc.Off
4225 // fieldIdx finds the index of the field referred to by the ODOT node n.
4226 func fieldIdx(n *Node) int {
4230 panic("ODOT's LHS is not a struct")
4234 for _, t1 := range t.Fields().Slice() {
4239 if t1.Offset != n.Xoffset {
4240 panic("field offset doesn't match")
4244 panic(fmt.Sprintf("can't find field in expr %s\n", n))
4246 // TODO: keep the result of this function somewhere in the ODOT Node
4247 // so we don't have to recompute it each time we need it.
4250 // ssaExport exports a bunch of compiler services for the ssa backend.
4251 type ssaExport struct {
4257 func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
4258 func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
4259 func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
4260 func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
4261 func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
4262 func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
4263 func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
4264 func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
4265 func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
4266 func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
4267 func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
4268 func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
4269 func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
4270 func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
4271 func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
4273 // StringData returns a symbol (a *Sym wrapped in an interface) which
4274 // is the data component of a global string constant containing s.
4275 func (*ssaExport) StringData(s string) interface{} {
4276 // TODO: is idealstring correct? It might not matter...
4277 _, data := stringsym(s)
4278 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
4281 func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
4282 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
4283 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
4287 func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4289 ptrType := Ptrto(Types[TUINT8])
4290 lenType := Types[TINT]
4291 if n.Class == PAUTO && !n.Addrtaken {
4292 // Split this string up into two separate variables.
4293 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4294 l := e.namedAuto(n.Sym.Name+".len", lenType)
4295 return ssa.LocalSlot{N: p, Type: ptrType, Off: 0}, ssa.LocalSlot{N: l, Type: lenType, Off: 0}
4297 // Return the two parts of the larger variable.
4298 return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off}, ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)}
4301 func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4303 t := Ptrto(Types[TUINT8])
4304 if n.Class == PAUTO && !n.Addrtaken {
4305 // Split this interface up into two separate variables.
4307 if n.Type.IsEmptyInterface() {
4310 c := e.namedAuto(n.Sym.Name+f, t)
4311 d := e.namedAuto(n.Sym.Name+".data", t)
4312 return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
4314 // Return the two parts of the larger variable.
4315 return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + int64(Widthptr)}
4318 func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
4320 ptrType := Ptrto(name.Type.ElemType().(*Type))
4321 lenType := Types[TINT]
4322 if n.Class == PAUTO && !n.Addrtaken {
4323 // Split this slice up into three separate variables.
4324 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4325 l := e.namedAuto(n.Sym.Name+".len", lenType)
4326 c := e.namedAuto(n.Sym.Name+".cap", lenType)
4327 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}
4329 // Return the three parts of the larger variable.
4330 return ssa.LocalSlot{N: n, Type: ptrType, Off: name.Off},
4331 ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(Widthptr)},
4332 ssa.LocalSlot{N: n, Type: lenType, Off: name.Off + int64(2*Widthptr)}
4335 func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4337 s := name.Type.Size() / 2
4344 if n.Class == PAUTO && !n.Addrtaken {
4345 // Split this complex up into two separate variables.
4346 c := e.namedAuto(n.Sym.Name+".real", t)
4347 d := e.namedAuto(n.Sym.Name+".imag", t)
4348 return ssa.LocalSlot{N: c, Type: t, Off: 0}, ssa.LocalSlot{N: d, Type: t, Off: 0}
4350 // Return the two parts of the larger variable.
4351 return ssa.LocalSlot{N: n, Type: t, Off: name.Off}, ssa.LocalSlot{N: n, Type: t, Off: name.Off + s}
4354 func (e *ssaExport) SplitInt64(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4357 if name.Type.IsSigned() {
4362 if n.Class == PAUTO && !n.Addrtaken {
4363 // Split this int64 up into two separate variables.
4364 h := e.namedAuto(n.Sym.Name+".hi", t)
4365 l := e.namedAuto(n.Sym.Name+".lo", Types[TUINT32])
4366 return ssa.LocalSlot{N: h, Type: t, Off: 0}, ssa.LocalSlot{N: l, Type: Types[TUINT32], Off: 0}
4368 // Return the two parts of the larger variable.
4369 // Assuming little endian (we don't support big endian 32-bit architecture yet)
4370 return ssa.LocalSlot{N: n, Type: t, Off: name.Off + 4}, ssa.LocalSlot{N: n, Type: Types[TUINT32], Off: name.Off}
4373 func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
4376 ft := st.FieldType(i)
4377 if n.Class == PAUTO && !n.Addrtaken {
4378 // Note: the _ field may appear several times. But
4379 // have no fear, identically-named but distinct Autos are
4380 // ok, albeit maybe confusing for a debugger.
4381 x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft)
4382 return ssa.LocalSlot{N: x, Type: ft, Off: 0}
4384 return ssa.LocalSlot{N: n, Type: ft, Off: name.Off + st.FieldOff(i)}
4387 // namedAuto returns a new AUTO variable with the given name and type.
4388 func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
4391 n := Nod(ONAME, nil, nil)
4401 n.Name.Curfn = Curfn
4402 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
4405 e.mustImplement = true
4410 func (e *ssaExport) CanSSA(t ssa.Type) bool {
4411 return canSSAType(t.(*Type))
4414 func (e *ssaExport) Line(line int32) string {
4415 return linestr(line)
4418 // Log logs a message from the compiler.
4419 func (e *ssaExport) Logf(msg string, args ...interface{}) {
4420 // If e was marked as unimplemented, anything could happen. Ignore.
4421 if e.log && !e.unimplemented {
4422 fmt.Printf(msg, args...)
4426 func (e *ssaExport) Log() bool {
4430 // Fatal reports a compiler error and exits.
4431 func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
4432 // If e was marked as unimplemented, anything could happen. Ignore.
4433 if !e.unimplemented {
4435 Fatalf(msg, args...)
4439 // Unimplemented reports that the function cannot be compiled.
4440 // It will be removed once SSA work is complete.
4441 func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
4442 if e.mustImplement {
4444 Fatalf(msg, args...)
4446 const alwaysLog = false // enable to calculate top unimplemented features
4447 if !e.unimplemented && (e.log || alwaysLog) {
4448 // first implementation failure, print explanation
4449 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4451 e.unimplemented = true
4454 // Warnl reports a "warning", which is usually flag-triggered
4455 // logging output for the benefit of tests.
4456 func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
4457 Warnl(line, fmt_, args...)
4460 func (e *ssaExport) Debug_checknil() bool {
4461 return Debug_checknil != 0
4464 func (n *Node) Typ() ssa.Type {