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.
15 "cmd/compile/internal/ssa"
17 "cmd/internal/obj/x86"
20 // Smallest possible faulting page at address zero.
21 const minZeroPage = 4096
23 var ssaConfig *ssa.Config
26 func initssa() *ssa.Config {
27 ssaExp.unimplemented = false
28 ssaExp.mustImplement = true
30 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
35 func shouldssa(fn *Node) bool {
36 if Thearch.Thestring != "amd64" {
40 // Environment variable control of SSA CG
41 // 1. IF GOSSAFUNC == current function name THEN
42 // compile this function with SSA and log output to ssa.html
44 // 2. IF GOSSAHASH == "" THEN
45 // compile this function (and everything else) with SSA
47 // 3. IF GOSSAHASH == "n" or "N"
48 // IF GOSSAPKG == current package name THEN
49 // compile this function (and everything in this package) with SSA
51 // use the old back end for this function.
52 // This is for compatibility with existing test harness and should go away.
54 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
55 // compile this function with SSA
57 // compile this function with the old back end.
59 // Plan is for 3 to be removed when the tests are revised.
60 // SSA is now default, and is disabled by setting
61 // GOSSAHASH to n or N, or selectively with strings of
64 name := fn.Func.Nname.Sym.Name
66 funcname := os.Getenv("GOSSAFUNC")
68 // If GOSSAFUNC is set, compile only that function.
69 return name == funcname
72 pkg := os.Getenv("GOSSAPKG")
74 // If GOSSAPKG is set, compile only that package.
75 return localpkg.Name == pkg
78 return initssa().DebugHashMatch("GOSSAHASH", name)
81 // buildssa builds an SSA function.
82 func buildssa(fn *Node) *ssa.Func {
83 name := fn.Func.Nname.Sym.Name
84 printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
86 fmt.Println("generating SSA for", name)
87 dumplist("buildssa-enter", fn.Func.Enter)
88 dumplist("buildssa-body", fn.Nbody)
89 dumplist("buildssa-exit", fn.Func.Exit)
96 // TODO(khr): build config just once at the start of the compiler binary
101 s.f = s.config.NewFunc()
103 s.exitCode = fn.Func.Exit
104 s.panics = map[funcLine]*ssa.Block{}
106 if name == os.Getenv("GOSSAFUNC") {
107 // TODO: tempfile? it is handy to have the location
108 // of this file be stable, so you can just reload in the browser.
109 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
110 // TODO: generate and print a mapping from nodes to values and blocks
114 s.config.HTML.Close()
118 // Allocate starting block
119 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
121 // Allocate starting values
122 s.labels = map[string]*ssaLabel{}
123 s.labeledNodes = map[*Node]*ssaLabel{}
124 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
125 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
126 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
128 s.startBlock(s.f.Entry)
129 s.vars[&memVar] = s.startmem
131 s.varsyms = map[*Node]interface{}{}
133 // Generate addresses of local declarations
134 s.decladdrs = map[*Node]*ssa.Value{}
135 for d := fn.Func.Dcl; d != nil; d = d.Next {
139 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
140 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
142 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
143 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
144 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
145 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
146 // This ends up wrong, have to do it at the PARAM node instead.
147 case PAUTO, PPARAMOUT:
148 // processed at each use, to prevent Addr coming
151 // local function - already handled by frontend
154 if n.Class&PHEAP != 0 {
157 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
161 // Convert the AST-based IR to the SSA-based IR
162 s.stmtList(fn.Func.Enter)
165 // fallthrough to exit
166 if s.curBlock != nil {
167 s.stmtList(s.exitCode)
170 b.Kind = ssa.BlockRet
174 // Check that we used all labels
175 for name, lab := range s.labels {
176 if !lab.used() && !lab.reported {
177 yyerrorl(int(lab.defNode.Lineno), "label %v defined and not used", name)
180 if lab.used() && !lab.defined() && !lab.reported {
181 yyerrorl(int(lab.useNode.Lineno), "label %v not defined", name)
186 // Check any forward gotos. Non-forward gotos have already been checked.
187 for _, n := range s.fwdGotos {
188 lab := s.labels[n.Left.Sym.Name]
189 // If the label is undefined, we have already have printed an error.
191 s.checkgoto(n, lab.defNode)
200 // Link up variable uses to variable definitions
201 s.linkForwardReferences()
203 // Don't carry reference this around longer than necessary
206 // Main call to ssa package to compile function
213 // configuration (arch) information
216 // function we're building
219 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
220 labels map[string]*ssaLabel
221 labeledNodes map[*Node]*ssaLabel
223 // gotos that jump forward; required for deferred checkgoto calls
225 // Code that must precede any return
226 // (e.g., copying value of heap-escaped paramout back to true paramout)
229 // unlabeled break and continue statement tracking
230 breakTo *ssa.Block // current target for plain break statement
231 continueTo *ssa.Block // current target for plain continue statement
233 // current location where we're interpreting the AST
236 // variable assignments in the current block (map from variable symbol to ssa value)
237 // *Node is the unique identifier (an ONAME Node) for the variable.
238 vars map[*Node]*ssa.Value
240 // all defined variables at the end of each block. Indexed by block ID.
241 defvars []map[*Node]*ssa.Value
243 // addresses of PPARAM and PPARAMOUT variables.
244 decladdrs map[*Node]*ssa.Value
246 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
247 varsyms map[*Node]interface{}
249 // starting values. Memory, stack pointer, and globals pointer
254 // line number stack. The current line number is top of stack
257 // list of panic calls by function name and line number.
258 // Used to deduplicate panic calls.
259 panics map[funcLine]*ssa.Block
261 // list of FwdRef values.
265 type funcLine struct {
270 type ssaLabel struct {
271 target *ssa.Block // block identified by this label
272 breakTarget *ssa.Block // block to break to in control flow node identified by this label
273 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
274 defNode *Node // label definition Node (OLABEL)
275 // Label use Node (OGOTO, OBREAK, OCONTINUE).
276 // Used only for error detection and reporting.
277 // There might be multiple uses, but we only need to track one.
279 reported bool // reported indicates whether an error has already been reported for this label
282 // defined reports whether the label has a definition (OLABEL node).
283 func (l *ssaLabel) defined() bool { return l.defNode != nil }
285 // used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
286 func (l *ssaLabel) used() bool { return l.useNode != nil }
288 // label returns the label associated with sym, creating it if necessary.
289 func (s *state) label(sym *Sym) *ssaLabel {
290 lab := s.labels[sym.Name]
293 s.labels[sym.Name] = lab
298 func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
299 func (s *state) Log() bool { return s.config.Log() }
300 func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
301 func (s *state) Unimplementedf(msg string, args ...interface{}) {
302 s.config.Unimplementedf(s.peekLine(), msg, args...)
304 func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
305 func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
308 // dummy node for the memory variable
309 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
311 // dummy nodes for temporary variables
312 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
313 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
314 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
315 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
316 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
319 // startBlock sets the current block we're generating code in to b.
320 func (s *state) startBlock(b *ssa.Block) {
321 if s.curBlock != nil {
322 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
325 s.vars = map[*Node]*ssa.Value{}
328 // endBlock marks the end of generating code for the current block.
329 // Returns the (former) current block. Returns nil if there is no current
330 // block, i.e. if no code flows to the current execution point.
331 func (s *state) endBlock() *ssa.Block {
336 for len(s.defvars) <= int(b.ID) {
337 s.defvars = append(s.defvars, nil)
339 s.defvars[b.ID] = s.vars
342 b.Line = s.peekLine()
346 // pushLine pushes a line number on the line number stack.
347 func (s *state) pushLine(line int32) {
348 s.line = append(s.line, line)
351 // popLine pops the top of the line number stack.
352 func (s *state) popLine() {
353 s.line = s.line[:len(s.line)-1]
356 // peekLine peek the top of the line number stack.
357 func (s *state) peekLine() int32 {
358 return s.line[len(s.line)-1]
361 func (s *state) Error(msg string, args ...interface{}) {
362 yyerrorl(int(s.peekLine()), msg, args...)
365 // newValue0 adds a new value with no arguments to the current block.
366 func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
367 return s.curBlock.NewValue0(s.peekLine(), op, t)
370 // newValue0A adds a new value with no arguments and an aux value to the current block.
371 func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
372 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
375 // newValue0I adds a new value with no arguments and an auxint value to the current block.
376 func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
377 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
380 // newValue1 adds a new value with one argument to the current block.
381 func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
382 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
385 // newValue1A adds a new value with one argument and an aux value to the current block.
386 func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
387 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
390 // newValue1I adds a new value with one argument and an auxint value to the current block.
391 func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
392 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
395 // newValue2 adds a new value with two arguments to the current block.
396 func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
397 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
400 // newValue2I adds a new value with two arguments and an auxint value to the current block.
401 func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
402 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
405 // newValue3 adds a new value with three arguments to the current block.
406 func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
407 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
410 // newValue3I adds a new value with three arguments and an auxint value to the current block.
411 func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
412 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
415 // entryNewValue0 adds a new value with no arguments to the entry block.
416 func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
417 return s.f.Entry.NewValue0(s.peekLine(), op, t)
420 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
421 func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
422 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
425 // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
426 func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
427 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
430 // entryNewValue1 adds a new value with one argument to the entry block.
431 func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
432 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
435 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
436 func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
437 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
440 // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
441 func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
442 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
445 // entryNewValue2 adds a new value with two arguments to the entry block.
446 func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
447 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
450 // const* routines add a new const value to the entry block.
451 func (s *state) constBool(c bool) *ssa.Value {
452 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
454 func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
455 return s.f.ConstInt8(s.peekLine(), t, c)
457 func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
458 return s.f.ConstInt16(s.peekLine(), t, c)
460 func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
461 return s.f.ConstInt32(s.peekLine(), t, c)
463 func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
464 return s.f.ConstInt64(s.peekLine(), t, c)
466 func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
467 return s.f.ConstFloat32(s.peekLine(), t, c)
469 func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
470 return s.f.ConstFloat64(s.peekLine(), t, c)
472 func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
473 if s.config.IntSize == 8 {
474 return s.constInt64(t, c)
476 if int64(int32(c)) != c {
477 s.Fatalf("integer constant too big %d", c)
479 return s.constInt32(t, int32(c))
482 // ssaStmtList converts the statement n to SSA and adds it to s.
483 func (s *state) stmtList(l *NodeList) {
484 for ; l != nil; l = l.Next {
489 // ssaStmt converts the statement n to SSA and adds it to s.
490 func (s *state) stmt(n *Node) {
494 // If s.curBlock is nil, then we're about to generate dead code.
495 // We can't just short-circuit here, though,
496 // because we check labels and gotos as part of SSA generation.
497 // Provide a block for the dead code so that we don't have
498 // to add special cases everywhere else.
499 if s.curBlock == nil {
500 dead := s.f.NewBlock(ssa.BlockPlain)
511 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
513 // Expression statements
514 case OCALLFUNC, OCALLMETH, OCALLINTER:
515 s.call(n, callNormal)
516 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
517 (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
518 n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo")) {
521 b.Kind = ssa.BlockExit
523 // TODO: never rewrite OPANIC to OCALLFUNC in the
524 // first place. Need to wait until all backends
528 s.call(n.Left, callDefer)
530 s.call(n.Left, callGo)
533 res, resok := s.dottype(n.Rlist.N, true)
534 s.assign(n.List.N, res, needwritebarrier(n.List.N, n.Rlist.N), false, n.Lineno)
535 s.assign(n.List.Next.N, resok, false, false, n.Lineno)
539 if n.Left.Class&PHEAP == 0 {
542 if compiling_runtime != 0 {
543 Fatalf("%v escapes to heap, not allowed in runtime.", n)
546 // TODO: the old pass hides the details of PHEAP
547 // variables behind ONAME nodes. Figure out if it's better
548 // to rewrite the tree and make the heapaddr construct explicit
549 // or to keep this detail hidden behind the scenes.
550 palloc := prealloc[n.Left]
552 palloc = callnew(n.Left.Type)
553 prealloc[n.Left] = palloc
556 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno)
562 // Empty identifier is valid but useless.
563 // See issues 11589, 11593.
569 // Associate label with its control flow node, if any
570 if ctl := n.Name.Defn; ctl != nil {
572 case OFOR, OSWITCH, OSELECT:
573 s.labeledNodes[ctl] = lab
580 s.Error("label %v already defined at %v", sym, Ctxt.Line(int(lab.defNode.Lineno)))
583 // The label might already have a target block via a goto.
584 if lab.target == nil {
585 lab.target = s.f.NewBlock(ssa.BlockPlain)
588 // go to that label (we pretend "label:" is preceded by "goto label")
590 b.AddEdgeTo(lab.target)
591 s.startBlock(lab.target)
597 if lab.target == nil {
598 lab.target = s.f.NewBlock(ssa.BlockPlain)
605 s.checkgoto(n, lab.defNode)
607 s.fwdGotos = append(s.fwdGotos, n)
611 b.AddEdgeTo(lab.target)
614 // Check whether we can generate static data rather than code.
615 // If so, ignore n and defer data generation until codegen.
616 // Failure to do this causes writes to readonly symbols.
617 if gen_as_init(n, true) {
619 if s.f.StaticData != nil {
620 data = s.f.StaticData.([]*Node)
622 s.f.StaticData = append(data, n)
635 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
636 // All literals with nonzero fields have already been
637 // rewritten during walk. Any that remain are just T{}
638 // or equivalents. Use the zero value.
640 Fatalf("literal with nonzero value in SSA: %v", rhs)
645 needwb := n.Op == OASWB && rhs != nil
646 deref := !canSSAType(t)
649 r = nil // Signal assign to use OpZero.
651 r = s.addr(rhs, false)
660 if rhs != nil && rhs.Op == OAPPEND {
661 // Yuck! The frontend gets rid of the write barrier, but we need it!
662 // At least, we need it in the case where growslice is called.
663 // TODO: Do the write barrier on just the growslice branch.
664 // TODO: just add a ptr graying to the end of growslice?
665 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
666 // They get similar wb-removal treatment in walk.go:OAS.
670 s.assign(n.Left, r, needwb, deref, n.Lineno)
673 bThen := s.f.NewBlock(ssa.BlockPlain)
674 bEnd := s.f.NewBlock(ssa.BlockPlain)
677 bElse = s.f.NewBlock(ssa.BlockPlain)
678 s.condBranch(n.Left, bThen, bElse, n.Likely)
680 s.condBranch(n.Left, bThen, bEnd, n.Likely)
685 if b := s.endBlock(); b != nil {
692 if b := s.endBlock(); b != nil {
700 s.stmtList(s.exitCode)
703 b.Kind = ssa.BlockRet
707 s.stmtList(s.exitCode)
710 b.Kind = ssa.BlockRetJmp
714 case OCONTINUE, OBREAK:
726 // plain break/continue
728 s.Error("%s is not in a loop", op)
731 // nothing to do; "to" is already the correct target
733 // labeled break/continue; look up the target
740 s.Error("%s label not defined: %v", op, sym)
746 to = lab.continueTarget
751 // Valid label but not usable with a break/continue here, e.g.:
757 s.Error("invalid %s label %v", op, sym)
767 // OFOR: for Ninit; Left; Right { Nbody }
768 bCond := s.f.NewBlock(ssa.BlockPlain)
769 bBody := s.f.NewBlock(ssa.BlockPlain)
770 bIncr := s.f.NewBlock(ssa.BlockPlain)
771 bEnd := s.f.NewBlock(ssa.BlockPlain)
773 // first, jump to condition test
777 // generate code to test condition
780 s.condBranch(n.Left, bBody, bEnd, 1)
783 b.Kind = ssa.BlockPlain
787 // set up for continue/break in body
788 prevContinue := s.continueTo
789 prevBreak := s.breakTo
792 lab := s.labeledNodes[n]
795 lab.continueTarget = bIncr
796 lab.breakTarget = bEnd
803 // tear down continue/break
804 s.continueTo = prevContinue
805 s.breakTo = prevBreak
807 lab.continueTarget = nil
808 lab.breakTarget = nil
811 // done with body, goto incr
812 if b := s.endBlock(); b != nil {
821 if b := s.endBlock(); b != nil {
826 case OSWITCH, OSELECT:
827 // These have been mostly rewritten by the front end into their Nbody fields.
828 // Our main task is to correctly hook up any break statements.
829 bEnd := s.f.NewBlock(ssa.BlockPlain)
831 prevBreak := s.breakTo
833 lab := s.labeledNodes[n]
836 lab.breakTarget = bEnd
839 // generate body code
842 s.breakTo = prevBreak
844 lab.breakTarget = nil
847 // OSWITCH never falls through (s.curBlock == nil here).
848 // OSELECT does not fall through if we're calling selectgo.
849 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
850 // In those latter cases, go to the code after the select.
851 if b := s.endBlock(); b != nil {
857 // Insert a varkill op to record that a variable is no longer live.
858 // We only care about liveness info at call sites, so putting the
859 // varkill in the store chain is enough to keep it correctly ordered
860 // with respect to call ops.
862 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
866 // Insert a varlive op to record that a variable is still live.
867 if !n.Left.Addrtaken {
868 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
870 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
877 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
881 type opAndType struct {
886 var opToSSA = map[opAndType]ssa.Op{
887 opAndType{OADD, TINT8}: ssa.OpAdd8,
888 opAndType{OADD, TUINT8}: ssa.OpAdd8,
889 opAndType{OADD, TINT16}: ssa.OpAdd16,
890 opAndType{OADD, TUINT16}: ssa.OpAdd16,
891 opAndType{OADD, TINT32}: ssa.OpAdd32,
892 opAndType{OADD, TUINT32}: ssa.OpAdd32,
893 opAndType{OADD, TPTR32}: ssa.OpAdd32,
894 opAndType{OADD, TINT64}: ssa.OpAdd64,
895 opAndType{OADD, TUINT64}: ssa.OpAdd64,
896 opAndType{OADD, TPTR64}: ssa.OpAdd64,
897 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
898 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
900 opAndType{OSUB, TINT8}: ssa.OpSub8,
901 opAndType{OSUB, TUINT8}: ssa.OpSub8,
902 opAndType{OSUB, TINT16}: ssa.OpSub16,
903 opAndType{OSUB, TUINT16}: ssa.OpSub16,
904 opAndType{OSUB, TINT32}: ssa.OpSub32,
905 opAndType{OSUB, TUINT32}: ssa.OpSub32,
906 opAndType{OSUB, TINT64}: ssa.OpSub64,
907 opAndType{OSUB, TUINT64}: ssa.OpSub64,
908 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
909 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
911 opAndType{ONOT, TBOOL}: ssa.OpNot,
913 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
914 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
915 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
916 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
917 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
918 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
919 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
920 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
921 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
922 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
924 opAndType{OCOM, TINT8}: ssa.OpCom8,
925 opAndType{OCOM, TUINT8}: ssa.OpCom8,
926 opAndType{OCOM, TINT16}: ssa.OpCom16,
927 opAndType{OCOM, TUINT16}: ssa.OpCom16,
928 opAndType{OCOM, TINT32}: ssa.OpCom32,
929 opAndType{OCOM, TUINT32}: ssa.OpCom32,
930 opAndType{OCOM, TINT64}: ssa.OpCom64,
931 opAndType{OCOM, TUINT64}: ssa.OpCom64,
933 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
934 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
935 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
936 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
938 opAndType{OMUL, TINT8}: ssa.OpMul8,
939 opAndType{OMUL, TUINT8}: ssa.OpMul8,
940 opAndType{OMUL, TINT16}: ssa.OpMul16,
941 opAndType{OMUL, TUINT16}: ssa.OpMul16,
942 opAndType{OMUL, TINT32}: ssa.OpMul32,
943 opAndType{OMUL, TUINT32}: ssa.OpMul32,
944 opAndType{OMUL, TINT64}: ssa.OpMul64,
945 opAndType{OMUL, TUINT64}: ssa.OpMul64,
946 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
947 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
949 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
950 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
952 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
953 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
954 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
955 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
956 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
957 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
959 opAndType{ODIV, TINT8}: ssa.OpDiv8,
960 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
961 opAndType{ODIV, TINT16}: ssa.OpDiv16,
962 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
963 opAndType{ODIV, TINT32}: ssa.OpDiv32,
964 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
965 opAndType{ODIV, TINT64}: ssa.OpDiv64,
966 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
968 opAndType{OMOD, TINT8}: ssa.OpMod8,
969 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
970 opAndType{OMOD, TINT16}: ssa.OpMod16,
971 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
972 opAndType{OMOD, TINT32}: ssa.OpMod32,
973 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
974 opAndType{OMOD, TINT64}: ssa.OpMod64,
975 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
977 opAndType{OAND, TINT8}: ssa.OpAnd8,
978 opAndType{OAND, TUINT8}: ssa.OpAnd8,
979 opAndType{OAND, TINT16}: ssa.OpAnd16,
980 opAndType{OAND, TUINT16}: ssa.OpAnd16,
981 opAndType{OAND, TINT32}: ssa.OpAnd32,
982 opAndType{OAND, TUINT32}: ssa.OpAnd32,
983 opAndType{OAND, TINT64}: ssa.OpAnd64,
984 opAndType{OAND, TUINT64}: ssa.OpAnd64,
986 opAndType{OOR, TINT8}: ssa.OpOr8,
987 opAndType{OOR, TUINT8}: ssa.OpOr8,
988 opAndType{OOR, TINT16}: ssa.OpOr16,
989 opAndType{OOR, TUINT16}: ssa.OpOr16,
990 opAndType{OOR, TINT32}: ssa.OpOr32,
991 opAndType{OOR, TUINT32}: ssa.OpOr32,
992 opAndType{OOR, TINT64}: ssa.OpOr64,
993 opAndType{OOR, TUINT64}: ssa.OpOr64,
995 opAndType{OXOR, TINT8}: ssa.OpXor8,
996 opAndType{OXOR, TUINT8}: ssa.OpXor8,
997 opAndType{OXOR, TINT16}: ssa.OpXor16,
998 opAndType{OXOR, TUINT16}: ssa.OpXor16,
999 opAndType{OXOR, TINT32}: ssa.OpXor32,
1000 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1001 opAndType{OXOR, TINT64}: ssa.OpXor64,
1002 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1004 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1005 opAndType{OEQ, TINT8}: ssa.OpEq8,
1006 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1007 opAndType{OEQ, TINT16}: ssa.OpEq16,
1008 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1009 opAndType{OEQ, TINT32}: ssa.OpEq32,
1010 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1011 opAndType{OEQ, TINT64}: ssa.OpEq64,
1012 opAndType{OEQ, TUINT64}: ssa.OpEq64,
1013 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1014 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
1015 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1016 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1017 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
1018 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
1019 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1020 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
1021 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1022 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
1024 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1025 opAndType{ONE, TINT8}: ssa.OpNeq8,
1026 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1027 opAndType{ONE, TINT16}: ssa.OpNeq16,
1028 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1029 opAndType{ONE, TINT32}: ssa.OpNeq32,
1030 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1031 opAndType{ONE, TINT64}: ssa.OpNeq64,
1032 opAndType{ONE, TUINT64}: ssa.OpNeq64,
1033 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1034 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
1035 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1036 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1037 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
1038 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
1039 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1040 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
1041 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1042 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
1044 opAndType{OLT, TINT8}: ssa.OpLess8,
1045 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1046 opAndType{OLT, TINT16}: ssa.OpLess16,
1047 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1048 opAndType{OLT, TINT32}: ssa.OpLess32,
1049 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1050 opAndType{OLT, TINT64}: ssa.OpLess64,
1051 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1052 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1053 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
1055 opAndType{OGT, TINT8}: ssa.OpGreater8,
1056 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1057 opAndType{OGT, TINT16}: ssa.OpGreater16,
1058 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1059 opAndType{OGT, TINT32}: ssa.OpGreater32,
1060 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1061 opAndType{OGT, TINT64}: ssa.OpGreater64,
1062 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1063 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1064 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
1066 opAndType{OLE, TINT8}: ssa.OpLeq8,
1067 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1068 opAndType{OLE, TINT16}: ssa.OpLeq16,
1069 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1070 opAndType{OLE, TINT32}: ssa.OpLeq32,
1071 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1072 opAndType{OLE, TINT64}: ssa.OpLeq64,
1073 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1074 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1075 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
1077 opAndType{OGE, TINT8}: ssa.OpGeq8,
1078 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1079 opAndType{OGE, TINT16}: ssa.OpGeq16,
1080 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1081 opAndType{OGE, TINT32}: ssa.OpGeq32,
1082 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1083 opAndType{OGE, TINT64}: ssa.OpGeq64,
1084 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1085 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1086 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
1088 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1089 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1090 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1091 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
1093 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
1096 func (s *state) concreteEtype(t *Type) EType {
1102 if s.config.IntSize == 8 {
1107 if s.config.IntSize == 8 {
1112 if s.config.PtrSize == 8 {
1119 func (s *state) ssaOp(op Op, t *Type) ssa.Op {
1120 etype := s.concreteEtype(t)
1121 x, ok := opToSSA[opAndType{op, etype}]
1123 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
1128 func floatForComplex(t *Type) *Type {
1130 return Types[TFLOAT32]
1132 return Types[TFLOAT64]
1136 type opAndTwoTypes struct {
1142 type twoTypes struct {
1147 type twoOpsAndType struct {
1150 intermediateType EType
1153 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1155 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1156 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1157 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1158 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1160 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1161 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1162 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1163 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1165 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1166 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1167 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1168 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1170 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1171 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1172 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1173 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1175 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1176 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1177 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1178 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1180 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1181 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1182 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1183 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1185 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1186 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1187 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1188 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1190 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1191 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1192 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1193 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1196 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1197 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1198 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1199 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1202 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1203 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1204 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1205 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1206 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1207 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1208 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1209 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1210 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1212 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1213 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1214 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1215 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1216 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1217 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1218 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1219 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1221 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1222 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1223 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1224 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1225 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1226 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1227 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1228 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1230 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1231 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1232 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1233 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1234 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1235 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1236 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1237 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1239 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1240 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1241 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1242 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1243 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1244 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1245 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1246 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1248 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1249 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1250 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1251 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1252 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1253 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1254 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1255 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1257 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1258 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1259 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1260 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1261 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1262 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1263 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1264 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1266 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1267 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1268 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1269 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1270 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1271 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1272 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1273 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1276 func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
1277 etype1 := s.concreteEtype(t)
1278 etype2 := s.concreteEtype(u)
1279 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1281 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
1286 func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
1287 etype1 := s.concreteEtype(t)
1288 x, ok := opToSSA[opAndType{op, etype1}]
1290 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
1295 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
1296 func (s *state) expr(n *Node) *ssa.Value {
1297 s.pushLine(n.Lineno)
1303 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
1304 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
1306 addr := s.addr(n, false)
1307 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
1309 if n.Class == PFUNC {
1310 // "value" of a function is the address of the function's closure
1311 sym := funcsym(n.Sym)
1312 aux := &ssa.ExternSymbol{n.Type, sym}
1313 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
1316 return s.variable(n, n.Type)
1318 addr := s.addr(n, false)
1319 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1321 addr := s.addr(n, false)
1322 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1324 switch n.Val().Ctype() {
1326 i := Mpgetfix(n.Val().U.(*Mpint))
1327 switch n.Type.Size() {
1329 return s.constInt8(n.Type, int8(i))
1331 return s.constInt16(n.Type, int16(i))
1333 return s.constInt32(n.Type, int32(i))
1335 return s.constInt64(n.Type, i)
1337 s.Fatalf("bad integer size %d", n.Type.Size())
1341 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1343 v := s.constBool(n.Val().U.(bool))
1344 // For some reason the frontend gets the line numbers of
1345 // CTBOOL literals totally wrong. Fix it here by grabbing
1346 // the line number of the enclosing AST node.
1347 if len(s.line) >= 2 {
1348 v.Line = s.line[len(s.line)-2]
1355 return s.entryNewValue0(ssa.OpConstSlice, t)
1356 case t.IsInterface():
1357 return s.entryNewValue0(ssa.OpConstInterface, t)
1359 return s.entryNewValue0(ssa.OpConstNil, t)
1362 f := n.Val().U.(*Mpflt)
1363 switch n.Type.Size() {
1365 return s.constFloat32(n.Type, mpgetflt32(f))
1367 return s.constFloat64(n.Type, mpgetflt(f))
1369 s.Fatalf("bad float size %d", n.Type.Size())
1373 c := n.Val().U.(*Mpcplx)
1376 switch n.Type.Size() {
1379 pt := Types[TFLOAT32]
1380 return s.newValue2(ssa.OpComplexMake, n.Type,
1381 s.constFloat32(pt, mpgetflt32(r)),
1382 s.constFloat32(pt, mpgetflt32(i)))
1386 pt := Types[TFLOAT64]
1387 return s.newValue2(ssa.OpComplexMake, n.Type,
1388 s.constFloat64(pt, mpgetflt(r)),
1389 s.constFloat64(pt, mpgetflt(i)))
1392 s.Fatalf("bad float size %d", n.Type.Size())
1397 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
1404 // Assume everything will work out, so set up our return value.
1405 // Anything interesting that happens from here is a fatal.
1408 // Special case for not confusing GC and liveness.
1409 // We don't want pointers accidentally classified
1410 // as not-pointers or vice-versa because of copy
1412 if to.IsPtr() != from.IsPtr() {
1413 return s.newValue2(ssa.OpConvert, to, x, s.mem())
1416 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1419 if to.Etype == TFUNC && from.IsPtr() {
1423 // named <--> unnamed type or typed <--> untyped const
1424 if from.Etype == to.Etype {
1428 // unsafe.Pointer <--> *T
1429 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1435 if from.Width != to.Width {
1436 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1439 if etypesign(from.Etype) != etypesign(to.Etype) {
1440 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
1445 // These appear to be fine, but they fail the
1446 // integer constraint below, so okay them here.
1447 // Sample non-integer conversion: map[string]string -> *uint8
1451 if etypesign(from.Etype) == 0 {
1452 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1456 // integer, same width, same sign
1461 ft := n.Left.Type // from type
1462 tt := n.Type // to type
1463 if ft.IsInteger() && tt.IsInteger() {
1465 if tt.Size() == ft.Size() {
1467 } else if tt.Size() < ft.Size() {
1469 switch 10*ft.Size() + tt.Size() {
1471 op = ssa.OpTrunc16to8
1473 op = ssa.OpTrunc32to8
1475 op = ssa.OpTrunc32to16
1477 op = ssa.OpTrunc64to8
1479 op = ssa.OpTrunc64to16
1481 op = ssa.OpTrunc64to32
1483 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1485 } else if ft.IsSigned() {
1487 switch 10*ft.Size() + tt.Size() {
1489 op = ssa.OpSignExt8to16
1491 op = ssa.OpSignExt8to32
1493 op = ssa.OpSignExt8to64
1495 op = ssa.OpSignExt16to32
1497 op = ssa.OpSignExt16to64
1499 op = ssa.OpSignExt32to64
1501 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1505 switch 10*ft.Size() + tt.Size() {
1507 op = ssa.OpZeroExt8to16
1509 op = ssa.OpZeroExt8to32
1511 op = ssa.OpZeroExt8to64
1513 op = ssa.OpZeroExt16to32
1515 op = ssa.OpZeroExt16to64
1517 op = ssa.OpZeroExt32to64
1519 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1522 return s.newValue1(op, n.Type, x)
1525 if ft.IsFloat() || tt.IsFloat() {
1526 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1528 s.Fatalf("weird float conversion %s -> %s", ft, tt)
1530 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1532 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1533 // normal case, not tripping over unsigned 64
1534 if op1 == ssa.OpCopy {
1535 if op2 == ssa.OpCopy {
1538 return s.newValue1(op2, n.Type, x)
1540 if op2 == ssa.OpCopy {
1541 return s.newValue1(op1, n.Type, x)
1543 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1545 // Tricky 64-bit unsigned cases.
1547 // therefore tt is float32 or float64, and ft is also unsigned
1549 return s.uint64Tofloat32(n, x, ft, tt)
1552 return s.uint64Tofloat64(n, x, ft, tt)
1554 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
1556 // therefore ft is float32 or float64, and tt is unsigned integer
1558 return s.float32ToUint64(n, x, ft, tt)
1561 return s.float64ToUint64(n, x, ft, tt)
1563 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1567 if ft.IsComplex() && tt.IsComplex() {
1569 if ft.Size() == tt.Size() {
1571 } else if ft.Size() == 8 && tt.Size() == 16 {
1572 op = ssa.OpCvt32Fto64F
1573 } else if ft.Size() == 16 && tt.Size() == 8 {
1574 op = ssa.OpCvt64Fto32F
1576 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1578 ftp := floatForComplex(ft)
1579 ttp := floatForComplex(tt)
1580 return s.newValue2(ssa.OpComplexMake, tt,
1581 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1582 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1585 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
1589 res, _ := s.dottype(n, false)
1593 case OLT, OEQ, ONE, OLE, OGE, OGT:
1595 b := s.expr(n.Right)
1596 if n.Left.Type.IsComplex() {
1597 pt := floatForComplex(n.Left.Type)
1598 op := s.ssaOp(OEQ, pt)
1599 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1600 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1601 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1606 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1608 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1611 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
1614 b := s.expr(n.Right)
1615 if n.Type.IsComplex() {
1616 mulop := ssa.OpMul64F
1617 addop := ssa.OpAdd64F
1618 subop := ssa.OpSub64F
1619 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1620 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1622 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1623 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1624 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1625 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1627 if pt != wt { // Widen for calculation
1628 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1629 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1630 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1631 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1634 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1635 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1637 if pt != wt { // Narrow to store back
1638 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1639 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1642 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1644 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1648 b := s.expr(n.Right)
1649 if n.Type.IsComplex() {
1650 // TODO this is not executed because the front-end substitutes a runtime call.
1651 // That probably ought to change; with modest optimization the widen/narrow
1652 // conversions could all be elided in larger expression trees.
1653 mulop := ssa.OpMul64F
1654 addop := ssa.OpAdd64F
1655 subop := ssa.OpSub64F
1656 divop := ssa.OpDiv64F
1657 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1658 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1660 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1661 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1662 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1663 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1665 if pt != wt { // Widen for calculation
1666 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1667 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1668 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1669 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1672 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1673 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1674 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1676 // TODO not sure if this is best done in wide precision or narrow
1677 // Double-rounding might be an issue.
1678 // Note that the pre-SSA implementation does the entire calculation
1679 // in wide format, so wide is compatible.
1680 xreal = s.newValue2(divop, wt, xreal, denom)
1681 ximag = s.newValue2(divop, wt, ximag, denom)
1683 if pt != wt { // Narrow to store back
1684 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1685 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1687 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1689 if n.Type.IsFloat() {
1690 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1692 // do a size-appropriate check for zero
1693 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1694 s.check(cmp, panicdivide)
1695 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1699 b := s.expr(n.Right)
1700 // do a size-appropriate check for zero
1701 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1702 s.check(cmp, panicdivide)
1703 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1706 b := s.expr(n.Right)
1707 if n.Type.IsComplex() {
1708 pt := floatForComplex(n.Type)
1709 op := s.ssaOp(n.Op, pt)
1710 return s.newValue2(ssa.OpComplexMake, n.Type,
1711 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1712 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1714 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1715 case OAND, OOR, OHMUL, OXOR:
1717 b := s.expr(n.Right)
1718 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1721 b := s.expr(n.Right)
1722 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
1726 if i <= 0 || i >= n.Type.Size()*8 {
1727 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1729 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
1730 case OANDAND, OOROR:
1731 // To implement OANDAND (and OOROR), we introduce a
1732 // new temporary variable to hold the result. The
1733 // variable is associated with the OANDAND node in the
1734 // s.vars table (normally variables are only
1735 // associated with ONAME nodes). We convert
1742 // Using var in the subsequent block introduces the
1743 // necessary phi variable.
1744 el := s.expr(n.Left)
1748 b.Kind = ssa.BlockIf
1750 // In theory, we should set b.Likely here based on context.
1751 // However, gc only gives us likeliness hints
1752 // in a single place, for plain OIF statements,
1753 // and passing around context is finnicky, so don't bother for now.
1755 bRight := s.f.NewBlock(ssa.BlockPlain)
1756 bResult := s.f.NewBlock(ssa.BlockPlain)
1757 if n.Op == OANDAND {
1759 b.AddEdgeTo(bResult)
1760 } else if n.Op == OOROR {
1761 b.AddEdgeTo(bResult)
1765 s.startBlock(bRight)
1766 er := s.expr(n.Right)
1770 b.AddEdgeTo(bResult)
1772 s.startBlock(bResult)
1773 return s.variable(n, Types[TBOOL])
1776 i := s.expr(n.Right)
1777 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
1782 if n.Type.IsComplex() {
1783 tp := floatForComplex(n.Type)
1784 negop := s.ssaOp(n.Op, tp)
1785 return s.newValue2(ssa.OpComplexMake, n.Type,
1786 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1787 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1789 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1790 case ONOT, OCOM, OSQRT:
1792 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1795 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
1797 return s.expr(n.Left)
1800 return s.addr(n.Left, n.Bounded)
1803 if int(n.Reg) != Thearch.REGSP {
1804 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1807 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1808 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1813 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1819 return s.newValue1I(ssa.OpStructSelect, n.Type, fieldIdx(n), v)
1821 p := s.addr(n, false)
1822 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1827 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
1828 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1832 case n.Left.Type.IsString():
1834 i := s.expr(n.Right)
1835 i = s.extendIndex(i)
1837 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1838 s.boundsCheck(i, len)
1840 ptrtyp := Ptrto(Types[TUINT8])
1841 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1842 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1843 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1844 case n.Left.Type.IsSlice():
1845 p := s.addr(n, false)
1846 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1847 case n.Left.Type.IsArray():
1848 // TODO: fix when we can SSA arrays of length 1.
1849 p := s.addr(n, false)
1850 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1852 s.Fatalf("bad type for index %v", n.Left.Type)
1858 case n.Left.Type.IsSlice():
1859 op := ssa.OpSliceLen
1863 return s.newValue1(op, Types[TINT], s.expr(n.Left))
1864 case n.Left.Type.IsString(): // string; not reachable for OCAP
1865 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
1866 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1867 return s.referenceTypeBuiltin(n, s.expr(n.Left))
1869 return s.constInt(Types[TINT], n.Left.Type.Bound)
1874 if n.Left.Type.IsSlice() {
1875 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1877 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1882 return s.newValue1(ssa.OpITab, n.Type, a)
1885 tab := s.expr(n.Left)
1886 data := s.expr(n.Right)
1887 // The frontend allows putting things like struct{*byte} in
1888 // the data portion of an eface. But we don't want struct{*byte}
1889 // as a register type because (among other reasons) the liveness
1890 // analysis is confused by the "fat" variables that result from
1891 // such types being spilled.
1892 // So here we ensure that we are selecting the underlying pointer
1893 // when we build an eface.
1894 // TODO: get rid of this now that structs can be SSA'd?
1895 for !data.Type.IsPtr() {
1897 case data.Type.IsArray():
1898 data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
1899 case data.Type.IsStruct():
1900 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1901 f := data.Type.FieldType(i)
1903 // eface type could also be struct{p *byte; q [0]int}
1906 data = s.newValue1I(ssa.OpStructSelect, f, i, data)
1910 s.Fatalf("type being put into an eface isn't a pointer")
1913 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1915 case OSLICE, OSLICEARR:
1918 if n.Right.Left != nil {
1919 i = s.extendIndex(s.expr(n.Right.Left))
1921 if n.Right.Right != nil {
1922 j = s.extendIndex(s.expr(n.Right.Right))
1924 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1925 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1929 if n.Right.Left != nil {
1930 i = s.extendIndex(s.expr(n.Right.Left))
1932 if n.Right.Right != nil {
1933 j = s.extendIndex(s.expr(n.Right.Right))
1935 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1936 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1937 case OSLICE3, OSLICE3ARR:
1940 if n.Right.Left != nil {
1941 i = s.extendIndex(s.expr(n.Right.Left))
1943 j := s.extendIndex(s.expr(n.Right.Right.Left))
1944 k := s.extendIndex(s.expr(n.Right.Right.Right))
1945 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1946 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1948 case OCALLFUNC, OCALLINTER, OCALLMETH:
1949 a := s.call(n, callNormal)
1950 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
1953 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
1956 // append(s, e1, e2, e3). Compile like:
1958 // newlen := len + 3
1959 // if newlen > s.cap {
1960 // ptr,_,cap = growslice(s, newlen)
1963 // *(ptr+len+1) = e2
1964 // *(ptr+len+2) = e3
1965 // makeslice(ptr,newlen,cap)
1971 slice := s.expr(n.List.N)
1973 // Allocate new blocks
1974 grow := s.f.NewBlock(ssa.BlockPlain)
1975 assign := s.f.NewBlock(ssa.BlockPlain)
1977 // Decide if we need to grow
1978 nargs := int64(count(n.List) - 1)
1979 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
1980 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
1981 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
1982 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
1983 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
1987 b.Kind = ssa.BlockIf
1988 b.Likely = ssa.BranchUnlikely
1995 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
1997 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
1999 s.vars[&ptrVar] = r[0]
2000 // Note: we don't need to read r[1], the result's length. It will be nl.
2001 // (or maybe we should, we just have to spill/restore nl otherwise?)
2002 s.vars[&capVar] = r[2]
2006 // assign new elements to slots
2007 s.startBlock(assign)
2010 args := make([]*ssa.Value, 0, nargs)
2011 store := make([]bool, 0, nargs)
2012 for l := n.List.Next; l != nil; l = l.Next {
2013 if canSSAType(l.N.Type) {
2014 args = append(args, s.expr(l.N))
2015 store = append(store, true)
2017 args = append(args, s.addr(l.N, false))
2018 store = append(store, false)
2022 p = s.variable(&ptrVar, pt) // generates phi for ptr
2023 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
2024 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
2025 // TODO: just one write barrier call for all of these writes?
2026 // TODO: maybe just one writeBarrier.enabled check?
2027 for i, arg := range args {
2028 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
2030 if haspointers(et) {
2031 s.insertWBstore(et, addr, arg, n.Lineno)
2033 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2036 if haspointers(et) {
2037 s.insertWBmove(et, addr, arg, n.Lineno)
2039 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2045 delete(s.vars, &ptrVar)
2046 delete(s.vars, &capVar)
2047 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2050 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
2055 // condBranch evaluates the boolean expression cond and branches to yes
2056 // if cond is true and no if cond is false.
2057 // This function is intended to handle && and || better than just calling
2058 // s.expr(cond) and branching on the result.
2059 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2060 if cond.Op == OANDAND {
2061 mid := s.f.NewBlock(ssa.BlockPlain)
2062 s.stmtList(cond.Ninit)
2063 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2065 s.condBranch(cond.Right, yes, no, likely)
2067 // Note: if likely==1, then both recursive calls pass 1.
2068 // If likely==-1, then we don't have enough information to decide
2069 // whether the first branch is likely or not. So we pass 0 for
2070 // the likeliness of the first branch.
2071 // TODO: have the frontend give us branch prediction hints for
2072 // OANDAND and OOROR nodes (if it ever has such info).
2074 if cond.Op == OOROR {
2075 mid := s.f.NewBlock(ssa.BlockPlain)
2076 s.stmtList(cond.Ninit)
2077 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2079 s.condBranch(cond.Right, yes, no, likely)
2081 // Note: if likely==-1, then both recursive calls pass -1.
2082 // If likely==1, then we don't have enough info to decide
2083 // the likelihood of the first branch.
2085 if cond.Op == ONOT {
2086 s.stmtList(cond.Ninit)
2087 s.condBranch(cond.Left, no, yes, -likely)
2092 b.Kind = ssa.BlockIf
2094 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2099 // assign does left = right.
2100 // Right has already been evaluated to ssa, left has not.
2101 // If deref is true, then we do left = *right instead (and right has already been nil-checked).
2102 // If deref is true and right == nil, just do left = 0.
2103 // Include a write barrier if wb is true.
2104 func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32) {
2105 if left.Op == ONAME && isblank(left) {
2112 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2114 if left.Op == ODOT {
2115 // We're assigning to a field of an ssa-able value.
2116 // We need to build a new structure with the new value for the
2117 // field we're assigning and the old values for the other fields.
2119 // type T struct {a, b, c int}
2122 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2124 // Grab information about the structure type.
2127 idx := fieldIdx(left)
2129 // Grab old value of structure.
2130 old := s.expr(left.Left)
2132 // Make new structure.
2133 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2135 // Add fields as args.
2136 for i := int64(0); i < nf; i++ {
2140 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), i, old))
2144 // Recursively assign the new value we've made to the base of the dot op.
2145 s.assign(left.Left, new, false, false, line)
2146 // TODO: do we need to update named values here?
2149 // Update variable assignment.
2150 s.vars[left] = right
2151 s.addNamedValue(left, right)
2154 // Left is not ssa-able. Compute its address.
2155 addr := s.addr(left, false)
2156 if left.Op == ONAME {
2157 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2160 // Treat as a mem->mem move.
2162 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2166 s.insertWBmove(t, addr, right, line)
2169 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2172 // Treat as a store.
2174 s.insertWBstore(t, addr, right, line)
2177 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
2180 // zeroVal returns the zero value for type t.
2181 func (s *state) zeroVal(t *Type) *ssa.Value {
2186 return s.constInt8(t, 0)
2188 return s.constInt16(t, 0)
2190 return s.constInt32(t, 0)
2192 return s.constInt64(t, 0)
2194 s.Fatalf("bad sized integer type %s", t)
2199 return s.constFloat32(t, 0)
2201 return s.constFloat64(t, 0)
2203 s.Fatalf("bad sized float type %s", t)
2208 z := s.constFloat32(Types[TFLOAT32], 0)
2209 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2211 z := s.constFloat64(Types[TFLOAT64], 0)
2212 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2214 s.Fatalf("bad sized complex type %s", t)
2218 return s.entryNewValue0A(ssa.OpConstString, t, "")
2220 return s.entryNewValue0(ssa.OpConstNil, t)
2222 return s.constBool(false)
2223 case t.IsInterface():
2224 return s.entryNewValue0(ssa.OpConstInterface, t)
2226 return s.entryNewValue0(ssa.OpConstSlice, t)
2229 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
2230 for i := int64(0); i < n; i++ {
2231 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2235 s.Unimplementedf("zero for type %v not implemented", t)
2242 callNormal callKind = iota
2247 // Calls the function n using the specified call type.
2248 // Returns the address of the return value (or nil if none).
2249 func (s *state) call(n *Node, k callKind) *ssa.Value {
2250 var sym *Sym // target symbol (if static)
2251 var closure *ssa.Value // ptr to closure to run (if dynamic)
2252 var codeptr *ssa.Value // ptr to target code (if dynamic)
2253 var rcvr *ssa.Value // receiver to set
2257 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2261 closure = s.expr(fn)
2263 if fn.Op != ODOTMETH {
2264 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2266 if fn.Right.Op != ONAME {
2267 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2269 if k == callNormal {
2275 closure = s.expr(&n2)
2276 // Note: receiver is already assigned in n.List, so we don't
2277 // want to set it here.
2279 if fn.Op != ODOTINTER {
2280 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2282 i := s.expr(fn.Left)
2283 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2284 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2285 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2286 if k == callNormal {
2287 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2291 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2294 stksize := fn.Type.Argwid // includes receiver
2296 // Run all argument assignments. The arg slots have already
2297 // been offset by the appropriate amount (+2*widthptr for go/defer,
2298 // +widthptr for interface calls).
2299 // For OCALLMETH, the receiver is set in these statements.
2302 // Set receiver (for interface calls)
2304 argStart := Ctxt.FixedFrameSize()
2305 if k != callNormal {
2306 argStart += int64(2 * Widthptr)
2308 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
2309 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
2313 if k != callNormal {
2314 // Write argsize and closure (args to Newproc/Deferproc).
2315 argsize := s.constInt32(Types[TUINT32], int32(stksize))
2316 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
2317 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
2318 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
2319 stksize += 2 * int64(Widthptr)
2323 bNext := s.f.NewBlock(ssa.BlockPlain)
2326 case k == callDefer:
2327 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2329 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2330 case closure != nil:
2331 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2332 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2333 case codeptr != nil:
2334 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2336 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2338 Fatalf("bad call type %s %v", opnames[n.Op], n)
2340 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2342 // Finish call block
2343 s.vars[&memVar] = call
2345 b.Kind = ssa.BlockCall
2349 // Start exit block, find address of result.
2352 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2353 if fp == nil || k != callNormal {
2354 // call has no return value. Continue with the next statement.
2357 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
2360 // etypesign returns the signed-ness of e, for integer/pointer etypes.
2361 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
2362 func etypesign(e EType) int8 {
2364 case TINT8, TINT16, TINT32, TINT64, TINT:
2366 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2372 // lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2373 // This improves the effectiveness of cse by using the same Aux values for the
2375 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2378 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2379 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2380 // these are the only valid types
2383 if lsym, ok := s.varsyms[n]; ok {
2391 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
2392 // The value that the returned Value represents is guaranteed to be non-nil.
2393 // If bounded is true then this address does not require a nil check for its operand
2394 // even if that would otherwise be implied.
2395 func (s *state) addr(n *Node, bounded bool) *ssa.Value {
2402 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
2403 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
2404 // TODO: Make OpAddr use AuxInt as well as Aux.
2406 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2415 if n.String() == ".fp" {
2416 // Special arg that points to the frame pointer.
2417 // (Used by the race detector, others?)
2418 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2419 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2421 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2424 // We need to regenerate the address of autos
2425 // at every use. This prevents LEA instructions
2426 // from occurring before the corresponding VarDef
2427 // op and confusing the liveness analysis into thinking
2428 // the variable is live at function entry.
2429 // TODO: I'm not sure if this really works or we're just
2430 // getting lucky. We might need a real dependency edge
2431 // between vardef and addr ops.
2432 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
2433 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2434 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
2435 // ensure that we reuse symbols for out parameters so
2436 // that cse works on their addresses
2437 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2438 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2439 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
2440 return s.expr(n.Name.Heapaddr)
2442 s.Unimplementedf("variable address class %v not implemented", n.Class)
2446 // indirect off a register
2447 // used for storing/loading arguments/returns to/from callees
2448 if int(n.Reg) != Thearch.REGSP {
2449 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2452 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
2454 if n.Left.Type.IsSlice() {
2456 i := s.expr(n.Right)
2457 i = s.extendIndex(i)
2458 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
2460 s.boundsCheck(i, len)
2462 p := s.newValue1(ssa.OpSlicePtr, t, a)
2463 return s.newValue2(ssa.OpPtrIndex, t, p, i)
2465 a := s.addr(n.Left, bounded)
2466 i := s.expr(n.Right)
2467 i = s.extendIndex(i)
2468 len := s.constInt(Types[TINT], n.Left.Type.Bound)
2470 s.boundsCheck(i, len)
2472 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
2481 p := s.addr(n.Left, bounded)
2482 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2488 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2490 return s.newValue2(ssa.OpAddPtr, t,
2491 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
2492 s.constInt(Types[TINT], n.Xoffset))
2495 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2496 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2499 // Recover original offset to address passed-in param value.
2501 original_p.Xoffset = n.Xoffset
2502 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
2503 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2505 addr := s.addr(n.Left, bounded)
2506 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
2507 case OCALLFUNC, OCALLINTER, OCALLMETH:
2508 return s.call(n, callNormal)
2511 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
2516 // canSSA reports whether n is SSA-able.
2517 // n must be an ONAME (or an ODOT sequence with an ONAME base).
2518 func canSSA(n *Node) bool {
2528 if n.Class&PHEAP != 0 {
2532 case PEXTERN, PPARAMOUT, PPARAMREF:
2535 if n.Class == PPARAM && n.String() == ".this" {
2536 // wrappers generated by genwrapper need to update
2537 // the .this pointer in place.
2540 return canSSAType(n.Type)
2541 // TODO: try to make more variables SSAable?
2544 // canSSA reports whether variables of type t are SSA-able.
2545 func canSSAType(t *Type) bool {
2547 if t.Width > int64(4*Widthptr) {
2548 // 4*Widthptr is an arbitrary constant. We want it
2549 // to be at least 3*Widthptr so slices can be registerized.
2550 // Too big and we'll introduce too much register pressure.
2558 // We can't do arrays because dynamic indexing is
2559 // not supported on SSA variables.
2560 // TODO: maybe allow if length is <=1? All indexes
2561 // are constant? Might be good for the arrays
2562 // introduced by the compiler for variadic functions.
2565 if countfield(t) > ssa.MaxStruct {
2568 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2569 if !canSSAType(t1.Type) {
2579 // nilCheck generates nil pointer checking code.
2580 // Starts a new block on return, unless nil checks are disabled.
2581 // Used only for automatically inserted nil checks,
2582 // not for user code like 'x != nil'.
2583 func (s *state) nilCheck(ptr *ssa.Value) {
2584 if Disable_checknil != 0 {
2587 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
2589 b.Kind = ssa.BlockCheck
2591 bNext := s.f.NewBlock(ssa.BlockPlain)
2596 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2597 // Starts a new block on return.
2598 func (s *state) boundsCheck(idx, len *ssa.Value) {
2599 if Debug['B'] != 0 {
2602 // TODO: convert index to full width?
2603 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2606 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
2607 s.check(cmp, Panicindex)
2610 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2611 // Starts a new block on return.
2612 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2613 if Debug['B'] != 0 {
2616 // TODO: convert index to full width?
2617 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2620 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
2621 s.check(cmp, panicslice)
2624 // If cmp (a bool) is true, panic using the given function.
2625 func (s *state) check(cmp *ssa.Value, fn *Node) {
2627 b.Kind = ssa.BlockIf
2629 b.Likely = ssa.BranchLikely
2630 bNext := s.f.NewBlock(ssa.BlockPlain)
2631 line := s.peekLine()
2632 bPanic := s.panics[funcLine{fn, line}]
2634 bPanic = s.f.NewBlock(ssa.BlockPlain)
2635 s.panics[funcLine{fn, line}] = bPanic
2636 s.startBlock(bPanic)
2637 // The panic call takes/returns memory to ensure that the right
2638 // memory state is observed if the panic happens.
2639 s.rtcall(fn, false, nil)
2646 // rtcall issues a call to the given runtime function fn with the listed args.
2647 // Returns a slice of results of the given result types.
2648 // The call is added to the end of the current block.
2649 // If returns is false, the block is marked as an exit block.
2650 // If returns is true, the block is marked as a call block. A new block
2651 // is started to load the return values.
2652 func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2653 // Write args to the stack
2654 var off int64 // TODO: arch-dependent starting offset?
2655 for _, arg := range args {
2657 off = Rnd(off, t.Alignment())
2660 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2663 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2666 off = Rnd(off, int64(Widthptr))
2669 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2670 s.vars[&memVar] = call
2675 b.Kind = ssa.BlockExit
2678 if len(results) > 0 {
2679 Fatalf("panic call can't have results")
2683 b.Kind = ssa.BlockCall
2685 bNext := s.f.NewBlock(ssa.BlockPlain)
2690 res := make([]*ssa.Value, len(results))
2691 for i, t := range results {
2692 off = Rnd(off, t.Alignment())
2695 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2697 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2700 off = Rnd(off, int64(Widthptr))
2702 // Remember how much callee stack space we needed.
2708 // insertWBmove inserts the assignment *left = *right including a write barrier.
2709 // t is the type being assigned.
2710 func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
2711 // if writeBarrier.enabled {
2712 // typedmemmove(&t, left, right)
2716 bThen := s.f.NewBlock(ssa.BlockPlain)
2717 bElse := s.f.NewBlock(ssa.BlockPlain)
2718 bEnd := s.f.NewBlock(ssa.BlockPlain)
2720 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2721 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2722 // TODO: select the .enabled field. It is currently first, so not needed for now.
2723 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2725 b.Kind = ssa.BlockIf
2726 b.Likely = ssa.BranchUnlikely
2732 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
2733 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2734 s.endBlock().AddEdgeTo(bEnd)
2737 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2738 s.endBlock().AddEdgeTo(bEnd)
2743 Warnl(int(line), "write barrier")
2747 // insertWBstore inserts the assignment *left = right including a write barrier.
2748 // t is the type being assigned.
2749 func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32) {
2750 // store scalar fields
2751 // if writeBarrier.enabled {
2752 // writebarrierptr for pointer fields
2754 // store pointer fields
2757 s.storeTypeScalars(t, left, right)
2759 bThen := s.f.NewBlock(ssa.BlockPlain)
2760 bElse := s.f.NewBlock(ssa.BlockPlain)
2761 bEnd := s.f.NewBlock(ssa.BlockPlain)
2763 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2764 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2765 // TODO: select the .enabled field. It is currently first, so not needed for now.
2766 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2768 b.Kind = ssa.BlockIf
2769 b.Likely = ssa.BranchUnlikely
2774 // Issue write barriers for pointer writes.
2776 s.storeTypePtrsWB(t, left, right)
2777 s.endBlock().AddEdgeTo(bEnd)
2779 // Issue regular stores for pointer writes.
2781 s.storeTypePtrs(t, left, right)
2782 s.endBlock().AddEdgeTo(bEnd)
2787 Warnl(int(line), "write barrier")
2791 // do *left = right for all scalar (non-pointer) parts of t.
2792 func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value) {
2794 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
2795 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
2796 case t.IsPtr() || t.IsMap() || t.IsChan():
2797 // no scalar fields.
2799 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
2800 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2801 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2803 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
2804 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
2805 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2806 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2807 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
2808 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
2809 case t.IsInterface():
2810 // itab field doesn't need a write barrier (even though it is a pointer).
2811 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
2812 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
2815 for i := int64(0); i < n; i++ {
2816 ft := t.FieldType(i)
2817 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2818 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2819 s.storeTypeScalars(ft.(*Type), addr, val)
2822 s.Fatalf("bad write barrier type %s", t)
2826 // do *left = right for all pointer parts of t.
2827 func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
2829 case t.IsPtr() || t.IsMap() || t.IsChan():
2830 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
2832 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2833 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2835 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2836 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2837 case t.IsInterface():
2838 // itab field is treated as a scalar.
2839 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2840 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2841 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
2844 for i := int64(0); i < n; i++ {
2845 ft := t.FieldType(i)
2846 if !haspointers(ft.(*Type)) {
2849 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2850 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2851 s.storeTypePtrs(ft.(*Type), addr, val)
2854 s.Fatalf("bad write barrier type %s", t)
2858 // do *left = right with a write barrier for all pointer parts of t.
2859 func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
2861 case t.IsPtr() || t.IsMap() || t.IsChan():
2862 s.rtcall(writebarrierptr, true, nil, left, right)
2864 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2865 s.rtcall(writebarrierptr, true, nil, left, ptr)
2867 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2868 s.rtcall(writebarrierptr, true, nil, left, ptr)
2869 case t.IsInterface():
2870 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2871 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2872 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
2875 for i := int64(0); i < n; i++ {
2876 ft := t.FieldType(i)
2877 if !haspointers(ft.(*Type)) {
2880 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2881 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2882 s.storeTypePtrsWB(ft.(*Type), addr, val)
2885 s.Fatalf("bad write barrier type %s", t)
2889 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2890 // i,j,k may be nil, in which case they are set to their default value.
2891 // t is a slice, ptr to array, or string type.
2892 func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2898 zero := s.constInt(Types[TINT], 0)
2902 ptrtype = Ptrto(elemtype)
2903 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2904 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2905 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2907 elemtype = Types[TUINT8]
2908 ptrtype = Ptrto(elemtype)
2909 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2910 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2913 if !t.Type.IsArray() {
2914 s.Fatalf("bad ptr to array in slice %v\n", t)
2916 elemtype = t.Type.Type
2917 ptrtype = Ptrto(elemtype)
2920 len = s.constInt(Types[TINT], t.Type.Bound)
2923 s.Fatalf("bad type in slice %v\n", t)
2926 // Set default values
2937 // Panic if slice indices are not in bounds.
2938 s.sliceBoundsCheck(i, j)
2940 s.sliceBoundsCheck(j, k)
2943 s.sliceBoundsCheck(k, cap)
2946 // Generate the following code assuming that indexes are in bounds.
2947 // The conditional is to make sure that we don't generate a slice
2948 // that points to the next object in memory.
2949 // rlen = (Sub64 j i)
2950 // rcap = (Sub64 k i)
2953 // p = (AddPtr ptr (Mul64 low (Const64 size)))
2955 // result = (SliceMake p size)
2956 subOp := s.ssaOp(OSUB, Types[TINT])
2957 neqOp := s.ssaOp(ONE, Types[TINT])
2958 mulOp := s.ssaOp(OMUL, Types[TINT])
2959 rlen := s.newValue2(subOp, Types[TINT], j, i)
2963 // Capacity of the result is unimportant. However, we use
2964 // rcap to test if we've generated a zero-length slice.
2965 // Use length of strings for that.
2970 rcap = s.newValue2(subOp, Types[TINT], k, i)
2973 s.vars[&ptrVar] = ptr
2975 // Generate code to test the resulting slice length.
2976 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
2979 b.Kind = ssa.BlockIf
2980 b.Likely = ssa.BranchLikely
2983 // Generate code for non-zero length slice case.
2984 nz := s.f.NewBlock(ssa.BlockPlain)
2988 if elemtype.Width == 1 {
2991 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
2993 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
2997 merge := s.f.NewBlock(ssa.BlockPlain)
3001 rptr := s.variable(&ptrVar, ptrtype)
3002 delete(s.vars, &ptrVar)
3003 return rptr, rlen, rcap
3006 type u2fcvtTab struct {
3007 geq, cvt2F, and, rsh, or, add ssa.Op
3008 one func(*state, ssa.Type, int64) *ssa.Value
3011 var u64_f64 u2fcvtTab = u2fcvtTab{
3013 cvt2F: ssa.OpCvt64to64F,
3015 rsh: ssa.OpRsh64Ux64,
3018 one: (*state).constInt64,
3021 var u64_f32 u2fcvtTab = u2fcvtTab{
3023 cvt2F: ssa.OpCvt64to32F,
3025 rsh: ssa.OpRsh64Ux64,
3028 one: (*state).constInt64,
3031 // Excess generality on a machine with 64-bit integer registers.
3032 // Not used on AMD64.
3033 var u32_f32 u2fcvtTab = u2fcvtTab{
3035 cvt2F: ssa.OpCvt32to32F,
3037 rsh: ssa.OpRsh32Ux32,
3040 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3041 return s.constInt32(t, int32(x))
3045 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3046 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3049 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3050 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3053 func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3055 // result = (floatY) x
3057 // y = uintX(x) ; y = x & 1
3058 // z = uintX(x) ; z = z >> 1
3061 // result = floatY(z)
3062 // result = result + result
3065 // Code borrowed from old code generator.
3066 // What's going on: large 64-bit "unsigned" looks like
3067 // negative number to hardware's integer-to-float
3068 // conversion. However, because the mantissa is only
3069 // 63 bits, we don't need the LSB, so instead we do an
3070 // unsigned right shift (divide by two), convert, and
3071 // double. However, before we do that, we need to be
3072 // sure that we do not lose a "1" if that made the
3073 // difference in the resulting rounding. Therefore, we
3074 // preserve it, and OR (not ADD) it back in. The case
3075 // that matters is when the eleven discarded bits are
3076 // equal to 10000000001; that rounds up, and the 1 cannot
3077 // be lost else it would round down if the LSB of the
3078 // candidate mantissa is 0.
3079 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3081 b.Kind = ssa.BlockIf
3083 b.Likely = ssa.BranchLikely
3085 bThen := s.f.NewBlock(ssa.BlockPlain)
3086 bElse := s.f.NewBlock(ssa.BlockPlain)
3087 bAfter := s.f.NewBlock(ssa.BlockPlain)
3091 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3094 bThen.AddEdgeTo(bAfter)
3098 one := cvttab.one(s, ft, 1)
3099 y := s.newValue2(cvttab.and, ft, x, one)
3100 z := s.newValue2(cvttab.rsh, ft, x, one)
3101 z = s.newValue2(cvttab.or, ft, z, y)
3102 a := s.newValue1(cvttab.cvt2F, tt, z)
3103 a1 := s.newValue2(cvttab.add, tt, a, a)
3106 bElse.AddEdgeTo(bAfter)
3108 s.startBlock(bAfter)
3109 return s.variable(n, n.Type)
3112 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3113 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3114 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3115 s.Fatalf("node must be a map or a channel")
3121 // return *((*int)n)
3123 // return *(((*int)n)+1)
3126 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
3127 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
3129 b.Kind = ssa.BlockIf
3131 b.Likely = ssa.BranchUnlikely
3133 bThen := s.f.NewBlock(ssa.BlockPlain)
3134 bElse := s.f.NewBlock(ssa.BlockPlain)
3135 bAfter := s.f.NewBlock(ssa.BlockPlain)
3137 // length/capacity of a nil map/chan is zero
3140 s.vars[n] = s.zeroVal(lenType)
3142 bThen.AddEdgeTo(bAfter)
3147 // length is stored in the first word for map/chan
3148 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3149 } else if n.Op == OCAP {
3150 // capacity is stored in the second word for chan
3151 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3152 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3154 s.Fatalf("op must be OLEN or OCAP")
3157 bElse.AddEdgeTo(bAfter)
3159 s.startBlock(bAfter)
3160 return s.variable(n, lenType)
3163 type f2uCvtTab struct {
3164 ltf, cvt2U, subf ssa.Op
3165 value func(*state, ssa.Type, float64) *ssa.Value
3168 var f32_u64 f2uCvtTab = f2uCvtTab{
3170 cvt2U: ssa.OpCvt32Fto64,
3172 value: (*state).constFloat32,
3175 var f64_u64 f2uCvtTab = f2uCvtTab{
3177 cvt2U: ssa.OpCvt64Fto64,
3179 value: (*state).constFloat64,
3182 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3183 return s.floatToUint(&f32_u64, n, x, ft, tt)
3185 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3186 return s.floatToUint(&f64_u64, n, x, ft, tt)
3189 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3190 // if x < 9223372036854775808.0 {
3191 // result = uintY(x)
3193 // y = x - 9223372036854775808.0
3195 // result = z | -9223372036854775808
3197 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3198 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3200 b.Kind = ssa.BlockIf
3202 b.Likely = ssa.BranchLikely
3204 bThen := s.f.NewBlock(ssa.BlockPlain)
3205 bElse := s.f.NewBlock(ssa.BlockPlain)
3206 bAfter := s.f.NewBlock(ssa.BlockPlain)
3210 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3213 bThen.AddEdgeTo(bAfter)
3217 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3218 y = s.newValue1(cvttab.cvt2U, tt, y)
3219 z := s.constInt64(tt, -9223372036854775808)
3220 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3223 bElse.AddEdgeTo(bAfter)
3225 s.startBlock(bAfter)
3226 return s.variable(n, n.Type)
3229 // ifaceType returns the value for the word containing the type.
3230 // n is the node for the interface expression.
3231 // v is the corresponding value.
3232 func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3233 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3235 if isnilinter(n.Type) {
3236 // Have *eface. The type is the first word in the struct.
3237 return s.newValue1(ssa.OpITab, byteptr, v)
3241 // The first word in the struct is the *itab.
3242 // If the *itab is nil, return 0.
3243 // Otherwise, the second word in the *itab is the type.
3245 tab := s.newValue1(ssa.OpITab, byteptr, v)
3246 s.vars[&typVar] = tab
3247 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3249 b.Kind = ssa.BlockIf
3250 b.Control = isnonnil
3251 b.Likely = ssa.BranchLikely
3253 bLoad := s.f.NewBlock(ssa.BlockPlain)
3254 bEnd := s.f.NewBlock(ssa.BlockPlain)
3258 bLoad.AddEdgeTo(bEnd)
3261 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3262 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3266 typ := s.variable(&typVar, byteptr)
3267 delete(s.vars, &typVar)
3271 // dottype generates SSA for a type assertion node.
3272 // commaok indicates whether to panic or return a bool.
3273 // If commaok is false, resok will be nil.
3274 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3275 iface := s.expr(n.Left)
3276 typ := s.ifaceType(n.Left, iface) // actual concrete type
3277 target := s.expr(typename(n.Type)) // target type
3278 if !isdirectiface(n.Type) {
3279 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3280 Fatalf("dottype needs a direct iface type %s", n.Type)
3283 if Debug_typeassert > 0 {
3284 Warnl(int(n.Lineno), "type assertion inlined")
3287 // TODO: If we have a nonempty interface and its itab field is nil,
3288 // then this test is redundant and ifaceType should just branch directly to bFail.
3289 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3291 b.Kind = ssa.BlockIf
3293 b.Likely = ssa.BranchLikely
3295 byteptr := Ptrto(Types[TUINT8])
3297 bOk := s.f.NewBlock(ssa.BlockPlain)
3298 bFail := s.f.NewBlock(ssa.BlockPlain)
3303 // on failure, panic by calling panicdottype
3305 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
3306 s.rtcall(panicdottype, false, nil, typ, target, taddr)
3308 // on success, return idata field
3310 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3313 // commaok is the more complicated case because we have
3314 // a control flow merge point.
3315 bEnd := s.f.NewBlock(ssa.BlockPlain)
3317 // type assertion succeeded
3319 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3320 s.vars[&okVar] = s.constBool(true)
3324 // type assertion failed
3326 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3327 s.vars[&okVar] = s.constBool(false)
3329 bFail.AddEdgeTo(bEnd)
3333 res = s.variable(&idataVar, byteptr)
3334 resok = s.variable(&okVar, Types[TBOOL])
3335 delete(s.vars, &idataVar)
3336 delete(s.vars, &okVar)
3340 // checkgoto checks that a goto from from to to does not
3341 // jump into a block or jump over variable declarations.
3342 // It is a copy of checkgoto in the pre-SSA backend,
3343 // modified only for line number handling.
3344 // TODO: document how this works and why it is designed the way it is.
3345 func (s *state) checkgoto(from *Node, to *Node) {
3346 if from.Sym == to.Sym {
3351 for fs := from.Sym; fs != nil; fs = fs.Link {
3355 for fs := to.Sym; fs != nil; fs = fs.Link {
3359 for ; nf > nt; nf-- {
3363 // decide what to complain about.
3364 // prefer to complain about 'into block' over declarations,
3365 // so scan backward to find most recent block or else dcl.
3370 for ; nt > nf; nt-- {
3389 lno := int(from.Left.Lineno)
3391 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
3393 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
3398 // variable returns the value of a variable at the current location.
3399 func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
3402 v = s.newValue0A(ssa.OpFwdRef, t, name)
3403 s.fwdRefs = append(s.fwdRefs, v)
3405 s.addNamedValue(name, v)
3410 func (s *state) mem() *ssa.Value {
3411 return s.variable(&memVar, ssa.TypeMem)
3414 func (s *state) linkForwardReferences() {
3415 // Build SSA graph. Each variable on its first use in a basic block
3416 // leaves a FwdRef in that block representing the incoming value
3417 // of that variable. This function links that ref up with possible definitions,
3418 // inserting Phi values as needed. This is essentially the algorithm
3419 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3420 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3422 // - We use FwdRef nodes to postpone phi building until the CFG is
3423 // completely built. That way we can avoid the notion of "sealed"
3425 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3426 for len(s.fwdRefs) > 0 {
3427 v := s.fwdRefs[len(s.fwdRefs)-1]
3428 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3433 // resolveFwdRef modifies v to be the variable's value at the start of its block.
3434 // v must be a FwdRef op.
3435 func (s *state) resolveFwdRef(v *ssa.Value) {
3437 name := v.Aux.(*Node)
3440 // Live variable at start of function.
3446 // Not SSAable. Load it.
3447 addr := s.decladdrs[name]
3449 // TODO: closure args reach here.
3450 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
3452 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3453 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3456 v.AddArgs(addr, s.startmem)
3459 if len(b.Preds) == 0 {
3460 // This block is dead; we have no predecessors and we're not the entry block.
3461 // It doesn't matter what we use here as long as it is well-formed.
3462 v.Op = ssa.OpUnknown
3465 // Find variable value on each predecessor.
3466 var argstore [4]*ssa.Value
3467 args := argstore[:0]
3468 for _, p := range b.Preds {
3469 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
3472 // Decide if we need a phi or not. We need a phi if there
3473 // are two different args (which are both not v).
3475 for _, a := range args {
3477 continue // self-reference
3480 continue // already have this witness
3483 // two witnesses, need a phi value
3488 w = a // save witness
3491 s.Fatalf("no witness for reachable phi %s", v)
3493 // One witness. Make v a copy of w.
3498 // lookupVarOutgoing finds the variable's value at the end of block b.
3499 func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
3500 m := s.defvars[b.ID]
3501 if v, ok := m[name]; ok {
3504 // The variable is not defined by b and we haven't
3505 // looked it up yet. Generate a FwdRef for the variable and return that.
3506 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3507 s.fwdRefs = append(s.fwdRefs, v)
3509 s.addNamedValue(name, v)
3513 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3514 if n.Class == Pxxx {
3515 // Don't track our dummy nodes (&memVar etc.).
3518 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3519 // Don't track autotmp_ variables.
3522 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3523 // TODO: can't handle auto compound objects with pointers yet.
3524 // The live variable analysis barfs because we don't put VARDEF
3525 // pseudos in the right place when we spill to these nodes.
3528 if n.Class == PAUTO && n.Xoffset != 0 {
3529 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3531 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3532 values, ok := s.f.NamedValues[loc]
3534 s.f.Names = append(s.f.Names, loc)
3536 s.f.NamedValues[loc] = append(values, v)
3539 // an unresolved branch
3540 type branch struct {
3541 p *obj.Prog // branch instruction
3542 b *ssa.Block // target
3545 type genState struct {
3546 // branches remembers all the branch instructions we've seen
3547 // and where they would like to go.
3550 // bstart remembers where each block starts (indexed by block ID)
3553 // deferBranches remembers all the defer branches we've seen.
3554 deferBranches []*obj.Prog
3556 // deferTarget remembers the (last) deferreturn call site.
3557 deferTarget *obj.Prog
3560 // genssa appends entries to ptxt for each instruction in f.
3561 // gcargs and gclocals are filled in with pointer maps for the frame.
3562 func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3565 e := f.Config.Frontend().(*ssaExport)
3566 // We're about to emit a bunch of Progs.
3567 // Since the only way to get here is to explicitly request it,
3568 // just fail on unimplemented instead of trying to unwind our mess.
3569 e.mustImplement = true
3571 // Remember where each block starts.
3572 s.bstart = make([]*obj.Prog, f.NumBlocks())
3574 var valueProgs map[*obj.Prog]*ssa.Value
3575 var blockProgs map[*obj.Prog]*ssa.Block
3576 const logProgs = true
3578 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3579 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3580 f.Logf("genssa %s\n", f.Name)
3581 blockProgs[Pc] = f.Blocks[0]
3584 // Emit basic blocks
3585 for i, b := range f.Blocks {
3587 // Emit values in block
3589 for _, v := range b.Values {
3593 for ; x != Pc; x = x.Link {
3598 // Emit control flow instructions for block
3600 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
3601 // If -N, leave next==nil so every block with successors
3602 // ends in a JMP (except call blocks - plive doesn't like
3603 // select{send,recv} followed by a JMP call). Helps keep
3604 // line numbers for otherwise empty blocks.
3605 next = f.Blocks[i+1]
3610 for ; x != Pc; x = x.Link {
3617 for _, br := range s.branches {
3618 br.p.To.Val = s.bstart[br.b.ID]
3620 if s.deferBranches != nil && s.deferTarget == nil {
3621 // This can happen when the function has a defer but
3622 // no return (because it has an infinite loop).
3626 for _, p := range s.deferBranches {
3627 p.To.Val = s.deferTarget
3631 for p := ptxt; p != nil; p = p.Link {
3633 if v, ok := valueProgs[p]; ok {
3635 } else if b, ok := blockProgs[p]; ok {
3638 s = " " // most value and branch strings are 2-3 characters long
3640 f.Logf("%s\t%s\n", s, p)
3642 if f.Config.HTML != nil {
3643 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3644 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3645 var buf bytes.Buffer
3646 buf.WriteString("<code>")
3647 buf.WriteString("<dl class=\"ssa-gen\">")
3648 for p := ptxt; p != nil; p = p.Link {
3649 buf.WriteString("<dt class=\"ssa-prog-src\">")
3650 if v, ok := valueProgs[p]; ok {
3651 buf.WriteString(v.HTML())
3652 } else if b, ok := blockProgs[p]; ok {
3653 buf.WriteString(b.HTML())
3655 buf.WriteString("</dt>")
3656 buf.WriteString("<dd class=\"ssa-prog\">")
3657 buf.WriteString(html.EscapeString(p.String()))
3658 buf.WriteString("</dd>")
3659 buf.WriteString("</li>")
3661 buf.WriteString("</dl>")
3662 buf.WriteString("</code>")
3663 f.Config.HTML.WriteColumn("genssa", buf.String())
3664 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3669 if f.StaticData != nil {
3670 for _, n := range f.StaticData.([]*Node) {
3671 if !gen_as_init(n, false) {
3672 Fatalf("non-static data marked as static: %v\n\n", n, f)
3677 // Allocate stack frame
3680 // Generate gc bitmaps.
3681 liveness(Curfn, ptxt, gcargs, gclocals)
3685 // Add frame prologue. Zero ambiguously live variables.
3686 Thearch.Defframe(ptxt)
3687 if Debug['f'] != 0 {
3691 // Remove leftover instrumentation from the instruction stream.
3694 f.Config.HTML.Close()
3697 // opregreg emits instructions for
3698 // dest := dest(To) op src(From)
3699 // and also returns the created obj.Prog so it
3700 // may be further adjusted (offset, scale, etc).
3701 func opregreg(op int, dest, src int16) *obj.Prog {
3703 p.From.Type = obj.TYPE_REG
3704 p.To.Type = obj.TYPE_REG
3710 func (s *genState) genValue(v *ssa.Value) {
3713 case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL, ssa.OpAMD64ADDW:
3715 r1 := regnum(v.Args[0])
3716 r2 := regnum(v.Args[1])
3719 p := Prog(v.Op.Asm())
3720 p.From.Type = obj.TYPE_REG
3722 p.To.Type = obj.TYPE_REG
3725 p := Prog(v.Op.Asm())
3726 p.From.Type = obj.TYPE_REG
3728 p.To.Type = obj.TYPE_REG
3733 case ssa.OpAMD64ADDQ:
3735 case ssa.OpAMD64ADDL:
3737 case ssa.OpAMD64ADDW:
3741 p.From.Type = obj.TYPE_MEM
3745 p.To.Type = obj.TYPE_REG
3748 // 2-address opcode arithmetic, symmetric
3749 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
3750 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
3751 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3752 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
3753 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
3754 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
3756 x := regnum(v.Args[0])
3757 y := regnum(v.Args[1])
3758 if x != r && y != r {
3759 opregreg(moveByType(v.Type), r, x)
3762 p := Prog(v.Op.Asm())
3763 p.From.Type = obj.TYPE_REG
3764 p.To.Type = obj.TYPE_REG
3771 // 2-address opcode arithmetic, not symmetric
3772 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
3774 x := regnum(v.Args[0])
3775 y := regnum(v.Args[1])
3778 // compute -(y-x) instead
3783 opregreg(moveByType(v.Type), r, x)
3785 opregreg(v.Op.Asm(), r, y)
3788 p := Prog(x86.ANEGQ) // TODO: use correct size? This is mostly a hack until regalloc does 2-address correctly
3789 p.To.Type = obj.TYPE_REG
3792 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3794 x := regnum(v.Args[0])
3795 y := regnum(v.Args[1])
3796 if y == r && x != r {
3797 // r/y := x op r/y, need to preserve x and rewrite to
3798 // r/y := r/y op x15
3799 x15 := int16(x86.REG_X15)
3800 // register move y to x15
3801 // register move x to y
3802 // rename y with x15
3803 opregreg(moveByType(v.Type), x15, y)
3804 opregreg(moveByType(v.Type), r, x)
3807 opregreg(moveByType(v.Type), r, x)
3809 opregreg(v.Op.Asm(), r, y)
3811 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
3812 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3813 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3814 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
3816 // Arg[0] is already in AX as it's the only register we allow
3817 // and AX is the only output
3818 x := regnum(v.Args[1])
3820 // CPU faults upon signed overflow, which occurs when most
3821 // negative int is divided by -1.
3823 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3824 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3825 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
3829 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
3832 // go ahead and sign extend to save doing it later
3835 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
3840 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
3845 c.From.Type = obj.TYPE_REG
3847 c.To.Type = obj.TYPE_CONST
3850 j.To.Type = obj.TYPE_BRANCH
3854 // for unsigned ints, we sign extend by setting DX = 0
3855 // signed ints were sign extended above
3856 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3857 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3858 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
3859 c := Prog(x86.AXORQ)
3860 c.From.Type = obj.TYPE_REG
3861 c.From.Reg = x86.REG_DX
3862 c.To.Type = obj.TYPE_REG
3863 c.To.Reg = x86.REG_DX
3866 p := Prog(v.Op.Asm())
3867 p.From.Type = obj.TYPE_REG
3870 // signed division, rest of the check for -1 case
3872 j2 := Prog(obj.AJMP)
3873 j2.To.Type = obj.TYPE_BRANCH
3876 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3877 v.Op == ssa.OpAMD64DIVW {
3880 n.To.Type = obj.TYPE_REG
3881 n.To.Reg = x86.REG_AX
3885 n.From.Type = obj.TYPE_REG
3886 n.From.Reg = x86.REG_DX
3887 n.To.Type = obj.TYPE_REG
3888 n.To.Reg = x86.REG_DX
3895 case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3896 ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
3897 // the frontend rewrites constant division by 8/16/32 bit integers into
3898 // HMUL by a constant
3899 // SSA rewrites generate the 64 bit versions
3901 // Arg[0] is already in AX as it's the only register we allow
3902 // and DX is the only output we care about (the high bits)
3903 p := Prog(v.Op.Asm())
3904 p.From.Type = obj.TYPE_REG
3905 p.From.Reg = regnum(v.Args[1])
3907 // IMULB puts the high portion in AH instead of DL,
3908 // so move it to DL for consistency
3909 if v.Type.Size() == 1 {
3910 m := Prog(x86.AMOVB)
3911 m.From.Type = obj.TYPE_REG
3912 m.From.Reg = x86.REG_AH
3913 m.To.Type = obj.TYPE_REG
3914 m.To.Reg = x86.REG_DX
3917 case ssa.OpAMD64AVGQU:
3918 // compute (x+y)/2 unsigned.
3919 // Do a 64-bit add, the overflow goes into the carry.
3920 // Shift right once and pull the carry back into the 63rd bit.
3922 x := regnum(v.Args[0])
3923 y := regnum(v.Args[1])
3924 if x != r && y != r {
3925 opregreg(moveByType(v.Type), r, x)
3928 p := Prog(x86.AADDQ)
3929 p.From.Type = obj.TYPE_REG
3930 p.To.Type = obj.TYPE_REG
3938 p.From.Type = obj.TYPE_CONST
3940 p.To.Type = obj.TYPE_REG
3943 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
3944 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
3945 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
3946 x := regnum(v.Args[0])
3949 if r == x86.REG_CX {
3950 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
3952 p := Prog(moveByType(v.Type))
3953 p.From.Type = obj.TYPE_REG
3955 p.To.Type = obj.TYPE_REG
3958 p := Prog(v.Op.Asm())
3959 p.From.Type = obj.TYPE_REG
3960 p.From.Reg = regnum(v.Args[1]) // should be CX
3961 p.To.Type = obj.TYPE_REG
3963 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
3965 a := regnum(v.Args[0])
3967 if v.AuxInt2Int64() == 1 {
3970 // Software optimization manual recommends add $1,reg.
3971 // But inc/dec is 1 byte smaller. ICC always uses inc
3972 // Clang/GCC choose depending on flags, but prefer add.
3973 // Experiments show that inc/dec is both a little faster
3974 // and make a binary a little smaller.
3975 case ssa.OpAMD64ADDQconst:
3977 case ssa.OpAMD64ADDLconst:
3979 case ssa.OpAMD64ADDWconst:
3983 p.To.Type = obj.TYPE_REG
3986 } else if v.AuxInt2Int64() == -1 {
3989 case ssa.OpAMD64ADDQconst:
3991 case ssa.OpAMD64ADDLconst:
3993 case ssa.OpAMD64ADDWconst:
3997 p.To.Type = obj.TYPE_REG
4001 p := Prog(v.Op.Asm())
4002 p.From.Type = obj.TYPE_CONST
4003 p.From.Offset = v.AuxInt2Int64()
4004 p.To.Type = obj.TYPE_REG
4011 case ssa.OpAMD64ADDQconst:
4013 case ssa.OpAMD64ADDLconst:
4015 case ssa.OpAMD64ADDWconst:
4019 p.From.Type = obj.TYPE_MEM
4021 p.From.Offset = v.AuxInt2Int64()
4022 p.To.Type = obj.TYPE_REG
4024 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
4026 x := regnum(v.Args[0])
4028 p := Prog(moveByType(v.Type))
4029 p.From.Type = obj.TYPE_REG
4031 p.To.Type = obj.TYPE_REG
4034 p := Prog(v.Op.Asm())
4035 p.From.Type = obj.TYPE_CONST
4036 p.From.Offset = v.AuxInt2Int64()
4037 p.To.Type = obj.TYPE_REG
4039 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
4040 // instead of using the MOVQ above.
4041 //p.From3 = new(obj.Addr)
4042 //p.From3.Type = obj.TYPE_REG
4043 //p.From3.Reg = regnum(v.Args[0])
4044 case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst:
4045 x := regnum(v.Args[0])
4047 // We have 3-op add (lea), so transforming a = b - const into
4048 // a = b + (- const), saves us 1 instruction. We can't fit
4049 // - (-1 << 31) into 4 bytes offset in lea.
4050 // We handle 2-address just fine below.
4051 if v.AuxInt2Int64() == -1<<31 || x == r {
4053 // This code compensates for the fact that the register allocator
4054 // doesn't understand 2-address instructions yet. TODO: fix that.
4055 p := Prog(moveByType(v.Type))
4056 p.From.Type = obj.TYPE_REG
4058 p.To.Type = obj.TYPE_REG
4061 p := Prog(v.Op.Asm())
4062 p.From.Type = obj.TYPE_CONST
4063 p.From.Offset = v.AuxInt2Int64()
4064 p.To.Type = obj.TYPE_REG
4066 } else if x == r && v.AuxInt2Int64() == -1 {
4068 // x = x - (-1) is the same as x++
4069 // See OpAMD64ADDQconst comments about inc vs add $1,reg
4071 case ssa.OpAMD64SUBQconst:
4073 case ssa.OpAMD64SUBLconst:
4075 case ssa.OpAMD64SUBWconst:
4079 p.To.Type = obj.TYPE_REG
4081 } else if x == r && v.AuxInt2Int64() == 1 {
4084 case ssa.OpAMD64SUBQconst:
4086 case ssa.OpAMD64SUBLconst:
4088 case ssa.OpAMD64SUBWconst:
4092 p.To.Type = obj.TYPE_REG
4097 case ssa.OpAMD64SUBQconst:
4099 case ssa.OpAMD64SUBLconst:
4101 case ssa.OpAMD64SUBWconst:
4105 p.From.Type = obj.TYPE_MEM
4107 p.From.Offset = -v.AuxInt2Int64()
4108 p.To.Type = obj.TYPE_REG
4112 case ssa.OpAMD64ADDBconst,
4113 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
4114 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
4115 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
4116 ssa.OpAMD64SUBBconst, ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst,
4117 ssa.OpAMD64SHLBconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst,
4118 ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst,
4119 ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst,
4120 ssa.OpAMD64ROLBconst:
4121 // This code compensates for the fact that the register allocator
4122 // doesn't understand 2-address instructions yet. TODO: fix that.
4123 x := regnum(v.Args[0])
4126 p := Prog(moveByType(v.Type))
4127 p.From.Type = obj.TYPE_REG
4129 p.To.Type = obj.TYPE_REG
4132 p := Prog(v.Op.Asm())
4133 p.From.Type = obj.TYPE_CONST
4134 p.From.Offset = v.AuxInt2Int64()
4135 p.To.Type = obj.TYPE_REG
4137 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
4139 p := Prog(v.Op.Asm())
4140 p.From.Type = obj.TYPE_REG
4142 p.To.Type = obj.TYPE_REG
4144 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
4145 p := Prog(x86.ALEAQ)
4146 p.From.Type = obj.TYPE_MEM
4147 p.From.Reg = regnum(v.Args[0])
4149 case ssa.OpAMD64LEAQ1:
4151 case ssa.OpAMD64LEAQ2:
4153 case ssa.OpAMD64LEAQ4:
4155 case ssa.OpAMD64LEAQ8:
4158 p.From.Index = regnum(v.Args[1])
4160 p.To.Type = obj.TYPE_REG
4161 p.To.Reg = regnum(v)
4162 case ssa.OpAMD64LEAQ:
4163 p := Prog(x86.ALEAQ)
4164 p.From.Type = obj.TYPE_MEM
4165 p.From.Reg = regnum(v.Args[0])
4167 p.To.Type = obj.TYPE_REG
4168 p.To.Reg = regnum(v)
4169 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
4170 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
4171 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
4172 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
4173 // Go assembler has swapped operands for UCOMISx relative to CMP,
4174 // must account for that right here.
4175 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
4176 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
4177 p := Prog(v.Op.Asm())
4178 p.From.Type = obj.TYPE_REG
4179 p.From.Reg = regnum(v.Args[0])
4180 p.To.Type = obj.TYPE_CONST
4181 p.To.Offset = v.AuxInt2Int64()
4182 case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
4183 p := Prog(v.Op.Asm())
4184 p.From.Type = obj.TYPE_CONST
4185 p.From.Offset = v.AuxInt2Int64()
4186 p.To.Type = obj.TYPE_REG
4187 p.To.Reg = regnum(v.Args[0])
4188 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
4190 p := Prog(v.Op.Asm())
4191 p.From.Type = obj.TYPE_CONST
4192 p.From.Offset = v.AuxInt2Int64()
4193 p.To.Type = obj.TYPE_REG
4195 // If flags are live at this instruction, suppress the
4196 // MOV $0,AX -> XOR AX,AX optimization.
4198 p.Mark |= x86.PRESERVEFLAGS
4200 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
4202 p := Prog(v.Op.Asm())
4203 p.From.Type = obj.TYPE_FCONST
4204 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
4205 p.To.Type = obj.TYPE_REG
4207 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload, ssa.OpAMD64MOVOload:
4208 p := Prog(v.Op.Asm())
4209 p.From.Type = obj.TYPE_MEM
4210 p.From.Reg = regnum(v.Args[0])
4212 p.To.Type = obj.TYPE_REG
4213 p.To.Reg = regnum(v)
4214 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
4215 p := Prog(v.Op.Asm())
4216 p.From.Type = obj.TYPE_MEM
4217 p.From.Reg = regnum(v.Args[0])
4220 p.From.Index = regnum(v.Args[1])
4221 p.To.Type = obj.TYPE_REG
4222 p.To.Reg = regnum(v)
4223 case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
4224 p := Prog(v.Op.Asm())
4225 p.From.Type = obj.TYPE_MEM
4226 p.From.Reg = regnum(v.Args[0])
4229 p.From.Index = regnum(v.Args[1])
4230 p.To.Type = obj.TYPE_REG
4231 p.To.Reg = regnum(v)
4232 case ssa.OpAMD64MOVWloadidx2:
4233 p := Prog(v.Op.Asm())
4234 p.From.Type = obj.TYPE_MEM
4235 p.From.Reg = regnum(v.Args[0])
4238 p.From.Index = regnum(v.Args[1])
4239 p.To.Type = obj.TYPE_REG
4240 p.To.Reg = regnum(v)
4241 case ssa.OpAMD64MOVBloadidx1:
4242 p := Prog(v.Op.Asm())
4243 p.From.Type = obj.TYPE_MEM
4244 p.From.Reg = regnum(v.Args[0])
4247 p.From.Index = regnum(v.Args[1])
4248 p.To.Type = obj.TYPE_REG
4249 p.To.Reg = regnum(v)
4250 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
4251 p := Prog(v.Op.Asm())
4252 p.From.Type = obj.TYPE_REG
4253 p.From.Reg = regnum(v.Args[1])
4254 p.To.Type = obj.TYPE_MEM
4255 p.To.Reg = regnum(v.Args[0])
4257 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
4258 p := Prog(v.Op.Asm())
4259 p.From.Type = obj.TYPE_REG
4260 p.From.Reg = regnum(v.Args[2])
4261 p.To.Type = obj.TYPE_MEM
4262 p.To.Reg = regnum(v.Args[0])
4264 p.To.Index = regnum(v.Args[1])
4266 case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
4267 p := Prog(v.Op.Asm())
4268 p.From.Type = obj.TYPE_REG
4269 p.From.Reg = regnum(v.Args[2])
4270 p.To.Type = obj.TYPE_MEM
4271 p.To.Reg = regnum(v.Args[0])
4273 p.To.Index = regnum(v.Args[1])
4275 case ssa.OpAMD64MOVWstoreidx2:
4276 p := Prog(v.Op.Asm())
4277 p.From.Type = obj.TYPE_REG
4278 p.From.Reg = regnum(v.Args[2])
4279 p.To.Type = obj.TYPE_MEM
4280 p.To.Reg = regnum(v.Args[0])
4282 p.To.Index = regnum(v.Args[1])
4284 case ssa.OpAMD64MOVBstoreidx1:
4285 p := Prog(v.Op.Asm())
4286 p.From.Type = obj.TYPE_REG
4287 p.From.Reg = regnum(v.Args[2])
4288 p.To.Type = obj.TYPE_MEM
4289 p.To.Reg = regnum(v.Args[0])
4291 p.To.Index = regnum(v.Args[1])
4293 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4294 p := Prog(v.Op.Asm())
4295 p.From.Type = obj.TYPE_CONST
4296 sc := v.AuxValAndOff()
4299 case ssa.OpAMD64MOVBstoreconst:
4301 case ssa.OpAMD64MOVWstoreconst:
4303 case ssa.OpAMD64MOVLstoreconst:
4305 case ssa.OpAMD64MOVQstoreconst:
4308 p.To.Type = obj.TYPE_MEM
4309 p.To.Reg = regnum(v.Args[0])
4310 addAux2(&p.To, v, sc.Off())
4311 case ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1:
4312 p := Prog(v.Op.Asm())
4313 p.From.Type = obj.TYPE_CONST
4314 sc := v.AuxValAndOff()
4316 case ssa.OpAMD64MOVBstoreconstidx1:
4317 p.From.Offset = int64(int8(sc.Val()))
4319 case ssa.OpAMD64MOVWstoreconstidx2:
4320 p.From.Offset = int64(int16(sc.Val()))
4322 case ssa.OpAMD64MOVLstoreconstidx4:
4323 p.From.Offset = int64(int32(sc.Val()))
4325 case ssa.OpAMD64MOVQstoreconstidx8:
4326 p.From.Offset = sc.Val()
4329 p.To.Type = obj.TYPE_MEM
4330 p.To.Reg = regnum(v.Args[0])
4331 p.To.Index = regnum(v.Args[1])
4332 addAux2(&p.To, v, sc.Off())
4333 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
4334 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
4335 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
4336 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
4337 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
4338 case ssa.OpAMD64DUFFZERO:
4339 p := Prog(obj.ADUFFZERO)
4340 p.To.Type = obj.TYPE_ADDR
4341 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
4342 p.To.Offset = v.AuxInt
4343 case ssa.OpAMD64MOVOconst:
4345 v.Unimplementedf("MOVOconst can only do constant=0")
4348 opregreg(x86.AXORPS, r, r)
4349 case ssa.OpAMD64DUFFCOPY:
4350 p := Prog(obj.ADUFFCOPY)
4351 p.To.Type = obj.TYPE_ADDR
4352 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
4353 p.To.Offset = v.AuxInt
4355 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
4356 if v.Type.IsMemory() {
4359 x := regnum(v.Args[0])
4362 opregreg(moveByType(v.Type), y, x)
4365 if v.Type.IsFlags() {
4366 v.Unimplementedf("load flags not implemented: %v", v.LongString())
4369 p := Prog(loadByType(v.Type))
4370 n, off := autoVar(v.Args[0])
4371 p.From.Type = obj.TYPE_MEM
4373 p.From.Sym = Linksym(n.Sym)
4375 if n.Class == PPARAM {
4376 p.From.Name = obj.NAME_PARAM
4377 p.From.Offset += n.Xoffset
4379 p.From.Name = obj.NAME_AUTO
4381 p.To.Type = obj.TYPE_REG
4382 p.To.Reg = regnum(v)
4384 case ssa.OpStoreReg:
4385 if v.Type.IsFlags() {
4386 v.Unimplementedf("store flags not implemented: %v", v.LongString())
4389 p := Prog(storeByType(v.Type))
4390 p.From.Type = obj.TYPE_REG
4391 p.From.Reg = regnum(v.Args[0])
4392 n, off := autoVar(v)
4393 p.To.Type = obj.TYPE_MEM
4395 p.To.Sym = Linksym(n.Sym)
4397 if n.Class == PPARAM {
4398 p.To.Name = obj.NAME_PARAM
4399 p.To.Offset += n.Xoffset
4401 p.To.Name = obj.NAME_AUTO
4404 // just check to make sure regalloc and stackalloc did it right
4405 if v.Type.IsMemory() {
4409 loc := f.RegAlloc[v.ID]
4410 for _, a := range v.Args {
4411 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
4412 v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
4416 // memory arg needs no code
4418 // input args need no code
4419 case ssa.OpAMD64LoweredGetClosurePtr:
4420 // Output is hardwired to DX only,
4421 // and DX contains the closure pointer on
4422 // closure entry, and this "instruction"
4423 // is scheduled to the very beginning
4424 // of the entry block.
4425 case ssa.OpAMD64LoweredGetG:
4427 // See the comments in cmd/internal/obj/x86/obj6.go
4428 // near CanUse1InsnTLS for a detailed explanation of these instructions.
4429 if x86.CanUse1InsnTLS(Ctxt) {
4431 p := Prog(x86.AMOVQ)
4432 p.From.Type = obj.TYPE_MEM
4433 p.From.Reg = x86.REG_TLS
4434 p.To.Type = obj.TYPE_REG
4438 // MOVQ (r)(TLS*1), r
4439 p := Prog(x86.AMOVQ)
4440 p.From.Type = obj.TYPE_REG
4441 p.From.Reg = x86.REG_TLS
4442 p.To.Type = obj.TYPE_REG
4444 q := Prog(x86.AMOVQ)
4445 q.From.Type = obj.TYPE_MEM
4447 q.From.Index = x86.REG_TLS
4449 q.To.Type = obj.TYPE_REG
4452 case ssa.OpAMD64CALLstatic:
4453 p := Prog(obj.ACALL)
4454 p.To.Type = obj.TYPE_MEM
4455 p.To.Name = obj.NAME_EXTERN
4456 p.To.Sym = Linksym(v.Aux.(*Sym))
4457 if Maxarg < v.AuxInt {
4460 case ssa.OpAMD64CALLclosure:
4461 p := Prog(obj.ACALL)
4462 p.To.Type = obj.TYPE_REG
4463 p.To.Reg = regnum(v.Args[0])
4464 if Maxarg < v.AuxInt {
4467 case ssa.OpAMD64CALLdefer:
4468 p := Prog(obj.ACALL)
4469 p.To.Type = obj.TYPE_MEM
4470 p.To.Name = obj.NAME_EXTERN
4471 p.To.Sym = Linksym(Deferproc.Sym)
4472 if Maxarg < v.AuxInt {
4475 // defer returns in rax:
4476 // 0 if we should continue executing
4477 // 1 if we should jump to deferreturn call
4478 p = Prog(x86.ATESTL)
4479 p.From.Type = obj.TYPE_REG
4480 p.From.Reg = x86.REG_AX
4481 p.To.Type = obj.TYPE_REG
4482 p.To.Reg = x86.REG_AX
4484 p.To.Type = obj.TYPE_BRANCH
4485 s.deferBranches = append(s.deferBranches, p)
4486 case ssa.OpAMD64CALLgo:
4487 p := Prog(obj.ACALL)
4488 p.To.Type = obj.TYPE_MEM
4489 p.To.Name = obj.NAME_EXTERN
4490 p.To.Sym = Linksym(Newproc.Sym)
4491 if Maxarg < v.AuxInt {
4494 case ssa.OpAMD64CALLinter:
4495 p := Prog(obj.ACALL)
4496 p.To.Type = obj.TYPE_REG
4497 p.To.Reg = regnum(v.Args[0])
4498 if Maxarg < v.AuxInt {
4501 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4502 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
4503 x := regnum(v.Args[0])
4506 p := Prog(moveByType(v.Type))
4507 p.From.Type = obj.TYPE_REG
4509 p.To.Type = obj.TYPE_REG
4512 p := Prog(v.Op.Asm())
4513 p.To.Type = obj.TYPE_REG
4515 case ssa.OpAMD64SQRTSD:
4516 p := Prog(v.Op.Asm())
4517 p.From.Type = obj.TYPE_REG
4518 p.From.Reg = regnum(v.Args[0])
4519 p.To.Type = obj.TYPE_REG
4520 p.To.Reg = regnum(v)
4521 case ssa.OpSP, ssa.OpSB:
4523 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4524 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4525 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
4526 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
4527 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
4528 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
4529 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
4530 p := Prog(v.Op.Asm())
4531 p.To.Type = obj.TYPE_REG
4532 p.To.Reg = regnum(v)
4534 case ssa.OpAMD64SETNEF:
4535 p := Prog(v.Op.Asm())
4536 p.To.Type = obj.TYPE_REG
4537 p.To.Reg = regnum(v)
4538 q := Prog(x86.ASETPS)
4539 q.To.Type = obj.TYPE_REG
4540 q.To.Reg = x86.REG_AX
4541 // TODO AORQ copied from old code generator, why not AORB?
4542 opregreg(x86.AORQ, regnum(v), x86.REG_AX)
4544 case ssa.OpAMD64SETEQF:
4545 p := Prog(v.Op.Asm())
4546 p.To.Type = obj.TYPE_REG
4547 p.To.Reg = regnum(v)
4548 q := Prog(x86.ASETPC)
4549 q.To.Type = obj.TYPE_REG
4550 q.To.Reg = x86.REG_AX
4551 // TODO AANDQ copied from old code generator, why not AANDB?
4552 opregreg(x86.AANDQ, regnum(v), x86.REG_AX)
4554 case ssa.OpAMD64InvertFlags:
4555 v.Fatalf("InvertFlags should never make it to codegen %v", v)
4556 case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
4557 v.Fatalf("Flag* ops should never make it to codegen %v", v)
4558 case ssa.OpAMD64REPSTOSQ:
4561 case ssa.OpAMD64REPMOVSQ:
4565 Gvardef(v.Aux.(*Node))
4567 gvarkill(v.Aux.(*Node))
4569 gvarlive(v.Aux.(*Node))
4570 case ssa.OpAMD64LoweredNilCheck:
4571 // Optimization - if the subsequent block has a load or store
4572 // at the same address, we don't need to issue this instruction.
4574 for _, w := range v.Block.Succs[0].Values {
4575 if w.Op == ssa.OpPhi {
4576 if w.Type.IsMemory() {
4581 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4582 // w doesn't use a store - can't be a memory op.
4585 if w.Args[len(w.Args)-1] != mem {
4586 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4589 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
4590 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
4591 ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload,
4592 ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload,
4593 ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVOload,
4594 ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVOstore:
4595 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
4596 if Debug_checknil != 0 && int(v.Line) > 1 {
4597 Warnl(int(v.Line), "removed nil check")
4601 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4602 off := ssa.ValAndOff(v.AuxInt).Off()
4603 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
4604 if Debug_checknil != 0 && int(v.Line) > 1 {
4605 Warnl(int(v.Line), "removed nil check")
4610 if w.Type.IsMemory() {
4611 if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
4616 // We can't delay the nil check past the next store.
4620 // Issue a load which will fault if the input is nil.
4621 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4622 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4623 // but it doesn't have false dependency on AX.
4624 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4625 // That trades clobbering flags for clobbering a register.
4626 p := Prog(x86.ATESTB)
4627 p.From.Type = obj.TYPE_REG
4628 p.From.Reg = x86.REG_AX
4629 p.To.Type = obj.TYPE_MEM
4630 p.To.Reg = regnum(v.Args[0])
4632 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
4633 Warnl(int(v.Line), "generated nil check")
4636 v.Unimplementedf("genValue not implemented: %s", v.LongString())
4640 // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
4641 func (s *genState) markMoves(b *ssa.Block) {
4642 flive := b.FlagsLiveAtEnd
4643 if b.Control != nil && b.Control.Type.IsFlags() {
4646 for i := len(b.Values) - 1; i >= 0; i-- {
4648 if flive && (v.Op == ssa.OpAMD64MOVWconst || v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
4649 // The "mark" is any non-nil Aux value.
4652 if v.Type.IsFlags() {
4655 for _, a := range v.Args {
4656 if a.Type.IsFlags() {
4663 // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4664 func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4666 // TODO: use zero register on archs that support it.
4667 p.From.Type = obj.TYPE_CONST
4669 p.To.Type = obj.TYPE_MEM
4671 p.To.Offset = offset
4673 nleft = nbytes - width
4674 return nleft, offset
4677 var blockJump = [...]struct {
4680 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4681 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4682 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4683 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4684 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4685 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4686 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4687 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4688 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4689 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
4690 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4691 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4694 type floatingEQNEJump struct {
4698 var eqfJumps = [2][2]floatingEQNEJump{
4699 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4700 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4702 var nefJumps = [2][2]floatingEQNEJump{
4703 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4704 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4707 func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4708 p := Prog(jumps.jump)
4709 p.To.Type = obj.TYPE_BRANCH
4711 branches = append(branches, branch{p, b.Succs[to]})
4715 // liblink reorders the instruction stream as it sees fit.
4716 // Pass along what we know so liblink can make use of it.
4717 // TODO: Once we've fully switched to SSA,
4718 // make liblink leave our output alone.
4720 case ssa.BranchUnlikely:
4721 p.From.Type = obj.TYPE_CONST
4723 case ssa.BranchLikely:
4724 p.From.Type = obj.TYPE_CONST
4730 func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
4734 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4735 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
4737 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4738 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4740 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4741 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4743 q.To.Type = obj.TYPE_BRANCH
4744 s.branches = append(s.branches, branch{q, b.Succs[1]})
4748 func (s *genState) genBlock(b, next *ssa.Block) {
4752 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
4753 if b.Succs[0] != next {
4755 p.To.Type = obj.TYPE_BRANCH
4756 s.branches = append(s.branches, branch{p, b.Succs[0]})
4759 Prog(obj.AUNDEF) // tell plive.go that we never reach here
4765 case ssa.BlockRetJmp:
4767 p.To.Type = obj.TYPE_MEM
4768 p.To.Name = obj.NAME_EXTERN
4769 p.To.Sym = Linksym(b.Aux.(*Sym))
4771 case ssa.BlockAMD64EQF:
4772 genFPJump(s, b, next, &eqfJumps)
4774 case ssa.BlockAMD64NEF:
4775 genFPJump(s, b, next, &nefJumps)
4777 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4778 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4779 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4780 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4781 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
4782 jmp := blockJump[b.Kind]
4787 p = Prog(jmp.invasm)
4789 p.To.Type = obj.TYPE_BRANCH
4790 s.branches = append(s.branches, branch{p, b.Succs[1]})
4793 p.To.Type = obj.TYPE_BRANCH
4794 s.branches = append(s.branches, branch{p, b.Succs[0]})
4797 p.To.Type = obj.TYPE_BRANCH
4798 s.branches = append(s.branches, branch{p, b.Succs[0]})
4800 q.To.Type = obj.TYPE_BRANCH
4801 s.branches = append(s.branches, branch{q, b.Succs[1]})
4804 // liblink reorders the instruction stream as it sees fit.
4805 // Pass along what we know so liblink can make use of it.
4806 // TODO: Once we've fully switched to SSA,
4807 // make liblink leave our output alone.
4809 case ssa.BranchUnlikely:
4810 p.From.Type = obj.TYPE_CONST
4812 case ssa.BranchLikely:
4813 p.From.Type = obj.TYPE_CONST
4818 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
4822 func (s *genState) deferReturn() {
4823 // Deferred calls will appear to be returning to
4824 // the CALL deferreturn(SB) that we are about to emit.
4825 // However, the stack trace code will show the line
4826 // of the instruction byte before the return PC.
4827 // To avoid that being an unrelated instruction,
4828 // insert an actual hardware NOP that will have the right line number.
4829 // This is different from obj.ANOP, which is a virtual no-op
4830 // that doesn't make it into the instruction stream.
4833 p := Prog(obj.ACALL)
4834 p.To.Type = obj.TYPE_MEM
4835 p.To.Name = obj.NAME_EXTERN
4836 p.To.Sym = Linksym(Deferreturn.Sym)
4839 // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4840 func addAux(a *obj.Addr, v *ssa.Value) {
4841 addAux2(a, v, v.AuxInt)
4843 func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
4844 if a.Type != obj.TYPE_MEM {
4845 v.Fatalf("bad addAux addr %s", a)
4847 // add integer offset
4850 // If no additional symbol offset, we're done.
4854 // Add symbol's offset from its base register.
4855 switch sym := v.Aux.(type) {
4856 case *ssa.ExternSymbol:
4857 a.Name = obj.NAME_EXTERN
4858 a.Sym = Linksym(sym.Sym.(*Sym))
4859 case *ssa.ArgSymbol:
4860 n := sym.Node.(*Node)
4861 a.Name = obj.NAME_PARAM
4863 a.Sym = Linksym(n.Orig.Sym)
4864 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
4865 case *ssa.AutoSymbol:
4866 n := sym.Node.(*Node)
4867 a.Name = obj.NAME_AUTO
4869 a.Sym = Linksym(n.Sym)
4871 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4875 // extendIndex extends v to a full int width.
4876 func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4877 size := v.Type.Size()
4878 if size == s.config.IntSize {
4881 if size > s.config.IntSize {
4882 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
4883 // the high word and branch to out-of-bounds failure if it is not 0.
4884 s.Unimplementedf("64->32 index truncation not implemented")
4888 // Extend value to the required size
4890 if v.Type.IsSigned() {
4891 switch 10*size + s.config.IntSize {
4893 op = ssa.OpSignExt8to32
4895 op = ssa.OpSignExt8to64
4897 op = ssa.OpSignExt16to32
4899 op = ssa.OpSignExt16to64
4901 op = ssa.OpSignExt32to64
4903 s.Fatalf("bad signed index extension %s", v.Type)
4906 switch 10*size + s.config.IntSize {
4908 op = ssa.OpZeroExt8to32
4910 op = ssa.OpZeroExt8to64
4912 op = ssa.OpZeroExt16to32
4914 op = ssa.OpZeroExt16to64
4916 op = ssa.OpZeroExt32to64
4918 s.Fatalf("bad unsigned index extension %s", v.Type)
4921 return s.newValue1(op, Types[TINT], v)
4924 // ssaRegToReg maps ssa register numbers to obj register numbers.
4925 var ssaRegToReg = [...]int16{
4958 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
4959 // TODO: arch-dependent
4962 // loadByType returns the load instruction of the given type.
4963 func loadByType(t ssa.Type) int {
4964 // For x86, there's no difference between load and store opcodes.
4965 return storeByType(t)
4968 // storeByType returns the store instruction of the given type.
4969 func storeByType(t ssa.Type) int {
4990 panic("bad store type")
4993 // moveByType returns the reg->reg move instruction of the given type.
4994 func moveByType(t ssa.Type) int {
4996 // Moving the whole sse2 register is faster
4997 // than moving just the correct low portion of it.
5010 panic("bad int register width")
5013 panic("bad register type")
5016 // regnum returns the register (in cmd/internal/obj numbering) to
5017 // which v has been allocated. Panics if v is not assigned to a
5019 // TODO: Make this panic again once it stops happening routinely.
5020 func regnum(v *ssa.Value) int16 {
5021 reg := v.Block.Func.RegAlloc[v.ID]
5023 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
5026 return ssaRegToReg[reg.(*ssa.Register).Num]
5029 // autoVar returns a *Node and int64 representing the auto variable and offset within it
5030 // where v should be spilled.
5031 func autoVar(v *ssa.Value) (*Node, int64) {
5032 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
5033 if v.Type.Size() > loc.Type.Size() {
5034 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
5036 return loc.N.(*Node), loc.Off
5039 // fieldIdx finds the index of the field referred to by the ODOT node n.
5040 func fieldIdx(n *Node) int64 {
5043 if t.Etype != TSTRUCT {
5044 panic("ODOT's LHS is not a struct")
5048 for t1 := t.Type; t1 != nil; t1 = t1.Down {
5049 if t1.Etype != TFIELD {
5050 panic("non-TFIELD in TSTRUCT")
5052 if t1.Sym != f.Sym {
5056 if t1.Width != n.Xoffset {
5057 panic("field offset doesn't match")
5061 panic(fmt.Sprintf("can't find field in expr %s\n", n))
5063 // TODO: keep the result of this fucntion somewhere in the ODOT Node
5064 // so we don't have to recompute it each time we need it.
5067 // ssaExport exports a bunch of compiler services for the ssa backend.
5068 type ssaExport struct {
5074 func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
5075 func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
5076 func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
5077 func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
5078 func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
5079 func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
5080 func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
5081 func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
5082 func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
5083 func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
5084 func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
5085 func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
5086 func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
5087 func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
5088 func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
5090 // StringData returns a symbol (a *Sym wrapped in an interface) which
5091 // is the data component of a global string constant containing s.
5092 func (*ssaExport) StringData(s string) interface{} {
5093 // TODO: is idealstring correct? It might not matter...
5094 _, data := stringsym(s)
5095 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
5098 func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
5099 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
5100 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
5104 func (e *ssaExport) CanSSA(t ssa.Type) bool {
5105 return canSSAType(t.(*Type))
5108 func (e *ssaExport) Line(line int32) string {
5109 return Ctxt.Line(int(line))
5112 // Log logs a message from the compiler.
5113 func (e *ssaExport) Logf(msg string, args ...interface{}) {
5114 // If e was marked as unimplemented, anything could happen. Ignore.
5115 if e.log && !e.unimplemented {
5116 fmt.Printf(msg, args...)
5120 func (e *ssaExport) Log() bool {
5124 // Fatal reports a compiler error and exits.
5125 func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
5126 // If e was marked as unimplemented, anything could happen. Ignore.
5127 if !e.unimplemented {
5129 Fatalf(msg, args...)
5133 // Unimplemented reports that the function cannot be compiled.
5134 // It will be removed once SSA work is complete.
5135 func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
5136 if e.mustImplement {
5138 Fatalf(msg, args...)
5140 const alwaysLog = false // enable to calculate top unimplemented features
5141 if !e.unimplemented && (e.log || alwaysLog) {
5142 // first implementation failure, print explanation
5143 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
5145 e.unimplemented = true
5148 // Warnl reports a "warning", which is usually flag-triggered
5149 // logging output for the benefit of tests.
5150 func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
5151 Warnl(line, fmt_, args...)
5154 func (e *ssaExport) Debug_checknil() bool {
5155 return Debug_checknil != 0
5158 func (n *Node) Typ() ssa.Type {