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.
16 "cmd/compile/internal/ssa"
18 "cmd/internal/obj/x86"
21 // Smallest possible faulting page at address zero.
22 const minZeroPage = 4096
24 // buildssa builds an SSA function
25 // and reports whether it should be used.
26 // Once the SSA implementation is complete,
27 // it will never return nil, and the bool can be removed.
28 func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
29 name := fn.Func.Nname.Sym.Name
30 gossahash := os.Getenv("GOSSAHASH")
31 usessa = strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
33 // Environment variable control of SSA CG
34 // 1. IF GOSSAFUNC == current function name THEN
35 // compile this function with SSA and log output to ssa.html
37 // 2. IF GOSSAHASH == "" THEN
38 // compile this function (and everything else) with SSA
40 // 3. IF GOSSAHASH == "n" or "N"
41 // IF GOSSAPKG == current package name THEN
42 // compile this function (and everything in this package) with SSA
44 // use the old back end for this function.
45 // This is for compatibility with existing test harness and should go away.
47 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
48 // compile this function with SSA
50 // compile this function with the old back end.
52 // Plan is for 3 to be removed when the tests are revised.
53 // SSA is now default, and is disabled by setting
54 // GOSSAHASH to n or N, or selectively with strings of
58 fmt.Println("generating SSA for", name)
59 dumplist("buildssa-enter", fn.Func.Enter)
60 dumplist("buildssa-body", fn.Nbody)
61 dumplist("buildssa-exit", fn.Func.Exit)
68 // TODO(khr): build config just once at the start of the compiler binary
72 s.config = ssa.NewConfig(Thearch.Thestring, &e, Ctxt)
73 s.f = s.config.NewFunc()
75 s.exitCode = fn.Func.Exit
76 s.panics = map[funcLine]*ssa.Block{}
78 if name == os.Getenv("GOSSAFUNC") {
79 // TODO: tempfile? it is handy to have the location
80 // of this file be stable, so you can just reload in the browser.
81 s.config.HTML = ssa.NewHTMLWriter("ssa.html", &s, name)
82 // TODO: generate and print a mapping from nodes to values and blocks
90 // We construct SSA using an algorithm similar to
91 // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
92 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
93 // TODO: check this comment
95 // Allocate starting block
96 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
98 // Allocate starting values
99 s.labels = map[string]*ssaLabel{}
100 s.labeledNodes = map[*Node]*ssaLabel{}
101 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
102 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
103 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
105 s.startBlock(s.f.Entry)
106 s.vars[&memVar] = s.startmem
108 s.varsyms = map[*Node]interface{}{}
110 // Generate addresses of local declarations
111 s.decladdrs = map[*Node]*ssa.Value{}
112 for d := fn.Func.Dcl; d != nil; d = d.Next {
116 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
117 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
119 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
120 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
121 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
122 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
123 // This ends up wrong, have to do it at the PARAM node instead.
124 case PAUTO, PPARAMOUT:
125 // processed at each use, to prevent Addr coming
128 // local function - already handled by frontend
131 if n.Class&PHEAP != 0 {
134 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
138 // Convert the AST-based IR to the SSA-based IR
139 s.stmtList(fn.Func.Enter)
142 // fallthrough to exit
143 if s.curBlock != nil {
144 s.stmtList(s.exitCode)
147 b.Kind = ssa.BlockRet
151 // Check that we used all labels
152 for name, lab := range s.labels {
153 if !lab.used() && !lab.reported {
154 yyerrorl(int(lab.defNode.Lineno), "label %v defined and not used", name)
157 if lab.used() && !lab.defined() && !lab.reported {
158 yyerrorl(int(lab.useNode.Lineno), "label %v not defined", name)
163 // Check any forward gotos. Non-forward gotos have already been checked.
164 for _, n := range s.fwdGotos {
165 lab := s.labels[n.Left.Sym.Name]
166 // If the label is undefined, we have already have printed an error.
168 s.checkgoto(n, lab.defNode)
176 // Link up variable uses to variable definitions
177 s.linkForwardReferences()
179 // Don't carry reference this around longer than necessary
182 // Main call to ssa package to compile function
185 // gossahash = "y" is historical/symmetric-with-"n" -- i.e., not really needed.
186 if usessa || gossahash == "" || gossahash == "y" || gossahash == "Y" {
189 if gossahash == "n" || gossahash == "N" {
190 if localpkg.Name != os.Getenv("GOSSAPKG") {
193 // Use everything in the package
197 // Check the hash of the name against a partial input hash.
198 // We use this feature to do a binary search within a package to
199 // find a function that is incorrectly compiled.
201 for _, b := range sha1.Sum([]byte(name)) {
202 hstr += fmt.Sprintf("%08b", b)
205 if strings.HasSuffix(hstr, gossahash) {
206 fmt.Printf("GOSSAHASH triggered %s\n", name)
210 // Iteratively try additional hashes to allow tests for multi-point
212 for i := 0; true; i++ {
213 ev := fmt.Sprintf("GOSSAHASH%d", i)
218 if strings.HasSuffix(hstr, evv) {
219 fmt.Printf("%s triggered %s\n", ev, name)
228 // configuration (arch) information
231 // function we're building
234 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
235 labels map[string]*ssaLabel
236 labeledNodes map[*Node]*ssaLabel
238 // gotos that jump forward; required for deferred checkgoto calls
240 // Code that must precede any return
241 // (e.g., copying value of heap-escaped paramout back to true paramout)
244 // unlabeled break and continue statement tracking
245 breakTo *ssa.Block // current target for plain break statement
246 continueTo *ssa.Block // current target for plain continue statement
248 // current location where we're interpreting the AST
251 // variable assignments in the current block (map from variable symbol to ssa value)
252 // *Node is the unique identifier (an ONAME Node) for the variable.
253 vars map[*Node]*ssa.Value
255 // all defined variables at the end of each block. Indexed by block ID.
256 defvars []map[*Node]*ssa.Value
258 // addresses of PPARAM and PPARAMOUT variables.
259 decladdrs map[*Node]*ssa.Value
261 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
262 varsyms map[*Node]interface{}
264 // starting values. Memory, stack pointer, and globals pointer
269 // line number stack. The current line number is top of stack
272 // list of panic calls by function name and line number.
273 // Used to deduplicate panic calls.
274 panics map[funcLine]*ssa.Block
277 type funcLine struct {
282 type ssaLabel struct {
283 target *ssa.Block // block identified by this label
284 breakTarget *ssa.Block // block to break to in control flow node identified by this label
285 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
286 defNode *Node // label definition Node (OLABEL)
287 // Label use Node (OGOTO, OBREAK, OCONTINUE).
288 // Used only for error detection and reporting.
289 // There might be multiple uses, but we only need to track one.
291 reported bool // reported indicates whether an error has already been reported for this label
294 // defined reports whether the label has a definition (OLABEL node).
295 func (l *ssaLabel) defined() bool { return l.defNode != nil }
297 // used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
298 func (l *ssaLabel) used() bool { return l.useNode != nil }
300 // label returns the label associated with sym, creating it if necessary.
301 func (s *state) label(sym *Sym) *ssaLabel {
302 lab := s.labels[sym.Name]
305 s.labels[sym.Name] = lab
310 func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
311 func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) }
312 func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
313 func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
314 func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
317 // dummy node for the memory variable
318 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
320 // dummy nodes for temporary variables
321 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
322 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
323 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
324 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
325 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
328 // startBlock sets the current block we're generating code in to b.
329 func (s *state) startBlock(b *ssa.Block) {
330 if s.curBlock != nil {
331 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
334 s.vars = map[*Node]*ssa.Value{}
337 // endBlock marks the end of generating code for the current block.
338 // Returns the (former) current block. Returns nil if there is no current
339 // block, i.e. if no code flows to the current execution point.
340 func (s *state) endBlock() *ssa.Block {
345 for len(s.defvars) <= int(b.ID) {
346 s.defvars = append(s.defvars, nil)
348 s.defvars[b.ID] = s.vars
351 b.Line = s.peekLine()
355 // pushLine pushes a line number on the line number stack.
356 func (s *state) pushLine(line int32) {
357 s.line = append(s.line, line)
360 // popLine pops the top of the line number stack.
361 func (s *state) popLine() {
362 s.line = s.line[:len(s.line)-1]
365 // peekLine peek the top of the line number stack.
366 func (s *state) peekLine() int32 {
367 return s.line[len(s.line)-1]
370 func (s *state) Error(msg string, args ...interface{}) {
371 yyerrorl(int(s.peekLine()), msg, args...)
374 // newValue0 adds a new value with no arguments to the current block.
375 func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
376 return s.curBlock.NewValue0(s.peekLine(), op, t)
379 // newValue0A adds a new value with no arguments and an aux value to the current block.
380 func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
381 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
384 // newValue0I adds a new value with no arguments and an auxint value to the current block.
385 func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
386 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
389 // newValue1 adds a new value with one argument to the current block.
390 func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
391 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
394 // newValue1A adds a new value with one argument and an aux value to the current block.
395 func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
396 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
399 // newValue1I adds a new value with one argument and an auxint value to the current block.
400 func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
401 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
404 // newValue2 adds a new value with two arguments to the current block.
405 func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
406 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
409 // newValue2I adds a new value with two arguments and an auxint value to the current block.
410 func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
411 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
414 // newValue3 adds a new value with three arguments to the current block.
415 func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
416 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
419 // newValue3I adds a new value with three arguments and an auxint value to the current block.
420 func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
421 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
424 // entryNewValue0 adds a new value with no arguments to the entry block.
425 func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
426 return s.f.Entry.NewValue0(s.peekLine(), op, t)
429 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
430 func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
431 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
434 // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
435 func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
436 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
439 // entryNewValue1 adds a new value with one argument to the entry block.
440 func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
441 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
444 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
445 func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
446 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
449 // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
450 func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
451 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
454 // entryNewValue2 adds a new value with two arguments to the entry block.
455 func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
456 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
459 // const* routines add a new const value to the entry block.
460 func (s *state) constBool(c bool) *ssa.Value {
461 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
463 func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
464 return s.f.ConstInt8(s.peekLine(), t, c)
466 func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
467 return s.f.ConstInt16(s.peekLine(), t, c)
469 func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
470 return s.f.ConstInt32(s.peekLine(), t, c)
472 func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
473 return s.f.ConstInt64(s.peekLine(), t, c)
475 func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
476 return s.f.ConstFloat32(s.peekLine(), t, c)
478 func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
479 return s.f.ConstFloat64(s.peekLine(), t, c)
481 func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
482 if s.config.IntSize == 8 {
483 return s.constInt64(t, c)
485 if int64(int32(c)) != c {
486 s.Fatalf("integer constant too big %d", c)
488 return s.constInt32(t, int32(c))
491 // ssaStmtList converts the statement n to SSA and adds it to s.
492 func (s *state) stmtList(l *NodeList) {
493 for ; l != nil; l = l.Next {
498 // ssaStmt converts the statement n to SSA and adds it to s.
499 func (s *state) stmt(n *Node) {
503 // If s.curBlock is nil, then we're about to generate dead code.
504 // We can't just short-circuit here, though,
505 // because we check labels and gotos as part of SSA generation.
506 // Provide a block for the dead code so that we don't have
507 // to add special cases everywhere else.
508 if s.curBlock == nil {
509 dead := s.f.NewBlock(ssa.BlockPlain)
520 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
522 // Expression statements
523 case OCALLFUNC, OCALLMETH, OCALLINTER:
524 s.call(n, callNormal)
526 s.call(n.Left, callDefer)
528 s.call(n.Left, callGo)
531 res, resok := s.dottype(n.Rlist.N, true)
532 s.assign(n.List.N, res, false)
533 s.assign(n.List.Next.N, resok, false)
537 if n.Left.Class&PHEAP == 0 {
540 if compiling_runtime != 0 {
541 Fatalf("%v escapes to heap, not allowed in runtime.", n)
544 // TODO: the old pass hides the details of PHEAP
545 // variables behind ONAME nodes. Figure out if it's better
546 // to rewrite the tree and make the heapaddr construct explicit
547 // or to keep this detail hidden behind the scenes.
548 palloc := prealloc[n.Left]
550 palloc = callnew(n.Left.Type)
551 prealloc[n.Left] = palloc
554 s.assign(n.Left.Name.Heapaddr, r, false)
560 // Empty identifier is valid but useless.
561 // See issues 11589, 11593.
567 // Associate label with its control flow node, if any
568 if ctl := n.Name.Defn; ctl != nil {
570 case OFOR, OSWITCH, OSELECT:
571 s.labeledNodes[ctl] = lab
578 s.Error("label %v already defined at %v", sym, Ctxt.Line(int(lab.defNode.Lineno)))
581 // The label might already have a target block via a goto.
582 if lab.target == nil {
583 lab.target = s.f.NewBlock(ssa.BlockPlain)
586 // go to that label (we pretend "label:" is preceded by "goto label")
588 b.AddEdgeTo(lab.target)
589 s.startBlock(lab.target)
595 if lab.target == nil {
596 lab.target = s.f.NewBlock(ssa.BlockPlain)
603 s.checkgoto(n, lab.defNode)
605 s.fwdGotos = append(s.fwdGotos, n)
609 b.AddEdgeTo(lab.target)
612 // Check whether we can generate static data rather than code.
613 // If so, ignore n and defer data generation until codegen.
614 // Failure to do this causes writes to readonly symbols.
615 if gen_as_init(n, true) {
617 if s.f.StaticData != nil {
618 data = s.f.StaticData.([]*Node)
620 s.f.StaticData = append(data, n)
625 if n.Right.Op == OSTRUCTLIT || n.Right.Op == OARRAYLIT {
626 // All literals with nonzero fields have already been
627 // rewritten during walk. Any that remain are just T{}
628 // or equivalents. Leave r = nil to get zeroing behavior.
629 if !iszero(n.Right) {
630 Fatalf("literal with nonzero value in SSA: %v", n.Right)
636 if n.Right != nil && n.Right.Op == OAPPEND {
637 // Yuck! The frontend gets rid of the write barrier, but we need it!
638 // At least, we need it in the case where growslice is called.
639 // TODO: Do the write barrier on just the growslice branch.
640 // TODO: just add a ptr graying to the end of growslice?
641 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
642 // They get similar wb-removal treatment in walk.go:OAS.
643 s.assign(n.Left, r, true)
646 s.assign(n.Left, r, n.Op == OASWB)
649 bThen := s.f.NewBlock(ssa.BlockPlain)
650 bEnd := s.f.NewBlock(ssa.BlockPlain)
653 bElse = s.f.NewBlock(ssa.BlockPlain)
654 s.condBranch(n.Left, bThen, bElse, n.Likely)
656 s.condBranch(n.Left, bThen, bEnd, n.Likely)
661 if b := s.endBlock(); b != nil {
668 if b := s.endBlock(); b != nil {
676 s.stmtList(s.exitCode)
679 b.Kind = ssa.BlockRet
683 s.stmtList(s.exitCode)
686 b.Kind = ssa.BlockRetJmp
690 case OCONTINUE, OBREAK:
702 // plain break/continue
704 s.Error("%s is not in a loop", op)
707 // nothing to do; "to" is already the correct target
709 // labeled break/continue; look up the target
716 s.Error("%s label not defined: %v", op, sym)
722 to = lab.continueTarget
727 // Valid label but not usable with a break/continue here, e.g.:
733 s.Error("invalid %s label %v", op, sym)
743 // OFOR: for Ninit; Left; Right { Nbody }
744 bCond := s.f.NewBlock(ssa.BlockPlain)
745 bBody := s.f.NewBlock(ssa.BlockPlain)
746 bIncr := s.f.NewBlock(ssa.BlockPlain)
747 bEnd := s.f.NewBlock(ssa.BlockPlain)
749 // first, jump to condition test
753 // generate code to test condition
756 s.condBranch(n.Left, bBody, bEnd, 1)
759 b.Kind = ssa.BlockPlain
763 // set up for continue/break in body
764 prevContinue := s.continueTo
765 prevBreak := s.breakTo
768 lab := s.labeledNodes[n]
771 lab.continueTarget = bIncr
772 lab.breakTarget = bEnd
779 // tear down continue/break
780 s.continueTo = prevContinue
781 s.breakTo = prevBreak
783 lab.continueTarget = nil
784 lab.breakTarget = nil
787 // done with body, goto incr
788 if b := s.endBlock(); b != nil {
797 if b := s.endBlock(); b != nil {
802 case OSWITCH, OSELECT:
803 // These have been mostly rewritten by the front end into their Nbody fields.
804 // Our main task is to correctly hook up any break statements.
805 bEnd := s.f.NewBlock(ssa.BlockPlain)
807 prevBreak := s.breakTo
809 lab := s.labeledNodes[n]
812 lab.breakTarget = bEnd
815 // generate body code
818 s.breakTo = prevBreak
820 lab.breakTarget = nil
823 if b := s.endBlock(); b != nil {
829 // Insert a varkill op to record that a variable is no longer live.
830 // We only care about liveness info at call sites, so putting the
831 // varkill in the store chain is enough to keep it correctly ordered
832 // with respect to call ops.
834 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
842 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
846 type opAndType struct {
851 var opToSSA = map[opAndType]ssa.Op{
852 opAndType{OADD, TINT8}: ssa.OpAdd8,
853 opAndType{OADD, TUINT8}: ssa.OpAdd8,
854 opAndType{OADD, TINT16}: ssa.OpAdd16,
855 opAndType{OADD, TUINT16}: ssa.OpAdd16,
856 opAndType{OADD, TINT32}: ssa.OpAdd32,
857 opAndType{OADD, TUINT32}: ssa.OpAdd32,
858 opAndType{OADD, TPTR32}: ssa.OpAdd32,
859 opAndType{OADD, TINT64}: ssa.OpAdd64,
860 opAndType{OADD, TUINT64}: ssa.OpAdd64,
861 opAndType{OADD, TPTR64}: ssa.OpAdd64,
862 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
863 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
865 opAndType{OSUB, TINT8}: ssa.OpSub8,
866 opAndType{OSUB, TUINT8}: ssa.OpSub8,
867 opAndType{OSUB, TINT16}: ssa.OpSub16,
868 opAndType{OSUB, TUINT16}: ssa.OpSub16,
869 opAndType{OSUB, TINT32}: ssa.OpSub32,
870 opAndType{OSUB, TUINT32}: ssa.OpSub32,
871 opAndType{OSUB, TINT64}: ssa.OpSub64,
872 opAndType{OSUB, TUINT64}: ssa.OpSub64,
873 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
874 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
876 opAndType{ONOT, TBOOL}: ssa.OpNot,
878 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
879 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
880 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
881 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
882 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
883 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
884 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
885 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
886 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
887 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
889 opAndType{OCOM, TINT8}: ssa.OpCom8,
890 opAndType{OCOM, TUINT8}: ssa.OpCom8,
891 opAndType{OCOM, TINT16}: ssa.OpCom16,
892 opAndType{OCOM, TUINT16}: ssa.OpCom16,
893 opAndType{OCOM, TINT32}: ssa.OpCom32,
894 opAndType{OCOM, TUINT32}: ssa.OpCom32,
895 opAndType{OCOM, TINT64}: ssa.OpCom64,
896 opAndType{OCOM, TUINT64}: ssa.OpCom64,
898 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
899 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
900 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
901 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
903 opAndType{OMUL, TINT8}: ssa.OpMul8,
904 opAndType{OMUL, TUINT8}: ssa.OpMul8,
905 opAndType{OMUL, TINT16}: ssa.OpMul16,
906 opAndType{OMUL, TUINT16}: ssa.OpMul16,
907 opAndType{OMUL, TINT32}: ssa.OpMul32,
908 opAndType{OMUL, TUINT32}: ssa.OpMul32,
909 opAndType{OMUL, TINT64}: ssa.OpMul64,
910 opAndType{OMUL, TUINT64}: ssa.OpMul64,
911 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
912 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
914 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
915 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
917 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
918 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
919 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
920 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
921 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
922 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
924 opAndType{ODIV, TINT8}: ssa.OpDiv8,
925 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
926 opAndType{ODIV, TINT16}: ssa.OpDiv16,
927 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
928 opAndType{ODIV, TINT32}: ssa.OpDiv32,
929 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
930 opAndType{ODIV, TINT64}: ssa.OpDiv64,
931 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
933 opAndType{OMOD, TINT8}: ssa.OpMod8,
934 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
935 opAndType{OMOD, TINT16}: ssa.OpMod16,
936 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
937 opAndType{OMOD, TINT32}: ssa.OpMod32,
938 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
939 opAndType{OMOD, TINT64}: ssa.OpMod64,
940 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
942 opAndType{OAND, TINT8}: ssa.OpAnd8,
943 opAndType{OAND, TUINT8}: ssa.OpAnd8,
944 opAndType{OAND, TINT16}: ssa.OpAnd16,
945 opAndType{OAND, TUINT16}: ssa.OpAnd16,
946 opAndType{OAND, TINT32}: ssa.OpAnd32,
947 opAndType{OAND, TUINT32}: ssa.OpAnd32,
948 opAndType{OAND, TINT64}: ssa.OpAnd64,
949 opAndType{OAND, TUINT64}: ssa.OpAnd64,
951 opAndType{OOR, TINT8}: ssa.OpOr8,
952 opAndType{OOR, TUINT8}: ssa.OpOr8,
953 opAndType{OOR, TINT16}: ssa.OpOr16,
954 opAndType{OOR, TUINT16}: ssa.OpOr16,
955 opAndType{OOR, TINT32}: ssa.OpOr32,
956 opAndType{OOR, TUINT32}: ssa.OpOr32,
957 opAndType{OOR, TINT64}: ssa.OpOr64,
958 opAndType{OOR, TUINT64}: ssa.OpOr64,
960 opAndType{OXOR, TINT8}: ssa.OpXor8,
961 opAndType{OXOR, TUINT8}: ssa.OpXor8,
962 opAndType{OXOR, TINT16}: ssa.OpXor16,
963 opAndType{OXOR, TUINT16}: ssa.OpXor16,
964 opAndType{OXOR, TINT32}: ssa.OpXor32,
965 opAndType{OXOR, TUINT32}: ssa.OpXor32,
966 opAndType{OXOR, TINT64}: ssa.OpXor64,
967 opAndType{OXOR, TUINT64}: ssa.OpXor64,
969 opAndType{OEQ, TBOOL}: ssa.OpEq8,
970 opAndType{OEQ, TINT8}: ssa.OpEq8,
971 opAndType{OEQ, TUINT8}: ssa.OpEq8,
972 opAndType{OEQ, TINT16}: ssa.OpEq16,
973 opAndType{OEQ, TUINT16}: ssa.OpEq16,
974 opAndType{OEQ, TINT32}: ssa.OpEq32,
975 opAndType{OEQ, TUINT32}: ssa.OpEq32,
976 opAndType{OEQ, TINT64}: ssa.OpEq64,
977 opAndType{OEQ, TUINT64}: ssa.OpEq64,
978 opAndType{OEQ, TINTER}: ssa.OpEqInter,
979 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
980 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
981 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
982 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
983 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
984 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
985 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
986 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
987 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
989 opAndType{ONE, TBOOL}: ssa.OpNeq8,
990 opAndType{ONE, TINT8}: ssa.OpNeq8,
991 opAndType{ONE, TUINT8}: ssa.OpNeq8,
992 opAndType{ONE, TINT16}: ssa.OpNeq16,
993 opAndType{ONE, TUINT16}: ssa.OpNeq16,
994 opAndType{ONE, TINT32}: ssa.OpNeq32,
995 opAndType{ONE, TUINT32}: ssa.OpNeq32,
996 opAndType{ONE, TINT64}: ssa.OpNeq64,
997 opAndType{ONE, TUINT64}: ssa.OpNeq64,
998 opAndType{ONE, TINTER}: ssa.OpNeqInter,
999 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
1000 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1001 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1002 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
1003 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
1004 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1005 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
1006 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1007 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
1009 opAndType{OLT, TINT8}: ssa.OpLess8,
1010 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1011 opAndType{OLT, TINT16}: ssa.OpLess16,
1012 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1013 opAndType{OLT, TINT32}: ssa.OpLess32,
1014 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1015 opAndType{OLT, TINT64}: ssa.OpLess64,
1016 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1017 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1018 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
1020 opAndType{OGT, TINT8}: ssa.OpGreater8,
1021 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1022 opAndType{OGT, TINT16}: ssa.OpGreater16,
1023 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1024 opAndType{OGT, TINT32}: ssa.OpGreater32,
1025 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1026 opAndType{OGT, TINT64}: ssa.OpGreater64,
1027 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1028 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1029 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
1031 opAndType{OLE, TINT8}: ssa.OpLeq8,
1032 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1033 opAndType{OLE, TINT16}: ssa.OpLeq16,
1034 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1035 opAndType{OLE, TINT32}: ssa.OpLeq32,
1036 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1037 opAndType{OLE, TINT64}: ssa.OpLeq64,
1038 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1039 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1040 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
1042 opAndType{OGE, TINT8}: ssa.OpGeq8,
1043 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1044 opAndType{OGE, TINT16}: ssa.OpGeq16,
1045 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1046 opAndType{OGE, TINT32}: ssa.OpGeq32,
1047 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1048 opAndType{OGE, TINT64}: ssa.OpGeq64,
1049 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1050 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1051 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
1053 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1054 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1055 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1056 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
1058 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
1061 func (s *state) concreteEtype(t *Type) EType {
1067 if s.config.IntSize == 8 {
1072 if s.config.IntSize == 8 {
1077 if s.config.PtrSize == 8 {
1084 func (s *state) ssaOp(op Op, t *Type) ssa.Op {
1085 etype := s.concreteEtype(t)
1086 x, ok := opToSSA[opAndType{op, etype}]
1088 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
1093 func floatForComplex(t *Type) *Type {
1095 return Types[TFLOAT32]
1097 return Types[TFLOAT64]
1101 type opAndTwoTypes struct {
1107 type twoTypes struct {
1112 type twoOpsAndType struct {
1115 intermediateType EType
1118 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1120 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1121 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1122 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1123 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1125 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1126 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1127 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1128 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1130 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1131 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1132 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1133 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1135 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1136 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1137 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1138 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1140 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1141 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1142 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1143 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1145 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1146 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1147 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1148 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1150 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1151 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1152 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1153 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1155 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1156 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1157 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1158 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1161 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1162 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1163 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1164 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1167 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1168 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1169 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1170 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1171 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1172 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1173 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1174 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1175 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1177 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1178 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1179 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1180 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1181 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1182 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1183 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1184 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1186 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1187 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1188 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1189 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1190 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1191 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1192 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1193 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1195 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1196 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1197 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1198 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1199 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1200 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1201 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1202 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1204 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1205 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1206 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1207 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1208 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1209 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1210 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1211 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1213 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1214 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1215 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1216 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1217 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1218 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1219 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1220 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1222 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1223 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1224 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1225 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1226 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1227 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1228 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1229 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1231 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1232 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1233 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1234 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1235 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1236 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1237 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1238 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1241 func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
1242 etype1 := s.concreteEtype(t)
1243 etype2 := s.concreteEtype(u)
1244 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1246 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
1251 func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
1252 etype1 := s.concreteEtype(t)
1253 x, ok := opToSSA[opAndType{op, etype1}]
1255 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
1260 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
1261 func (s *state) expr(n *Node) *ssa.Value {
1262 s.pushLine(n.Lineno)
1268 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
1269 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
1271 addr := s.addr(n, false)
1272 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
1274 if n.Class == PFUNC {
1275 // "value" of a function is the address of the function's closure
1276 sym := funcsym(n.Sym)
1277 aux := &ssa.ExternSymbol{n.Type, sym}
1278 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
1281 return s.variable(n, n.Type)
1283 addr := s.addr(n, false)
1284 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1286 addr := s.addr(n, false)
1287 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1289 switch n.Val().Ctype() {
1291 i := Mpgetfix(n.Val().U.(*Mpint))
1292 switch n.Type.Size() {
1294 return s.constInt8(n.Type, int8(i))
1296 return s.constInt16(n.Type, int16(i))
1298 return s.constInt32(n.Type, int32(i))
1300 return s.constInt64(n.Type, i)
1302 s.Fatalf("bad integer size %d", n.Type.Size())
1306 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1308 return s.constBool(n.Val().U.(bool))
1313 return s.entryNewValue0(ssa.OpConstSlice, t)
1314 case t.IsInterface():
1315 return s.entryNewValue0(ssa.OpConstInterface, t)
1317 return s.entryNewValue0(ssa.OpConstNil, t)
1320 f := n.Val().U.(*Mpflt)
1321 switch n.Type.Size() {
1323 // -0.0 literals need to be treated as if they were 0.0, adding 0.0 here
1324 // accomplishes this while not affecting other values.
1325 return s.constFloat32(n.Type, mpgetflt32(f)+0.0)
1327 return s.constFloat64(n.Type, mpgetflt(f)+0.0)
1329 s.Fatalf("bad float size %d", n.Type.Size())
1333 c := n.Val().U.(*Mpcplx)
1336 switch n.Type.Size() {
1339 pt := Types[TFLOAT32]
1340 // -0.0 literals need to be treated as if they were 0.0, adding 0.0 here
1341 // accomplishes this while not affecting other values.
1342 return s.newValue2(ssa.OpComplexMake, n.Type,
1343 s.constFloat32(pt, mpgetflt32(r)+0.0),
1344 s.constFloat32(pt, mpgetflt32(i)+0.0))
1348 pt := Types[TFLOAT64]
1349 return s.newValue2(ssa.OpComplexMake, n.Type,
1350 s.constFloat64(pt, mpgetflt(r)+0.0),
1351 s.constFloat64(pt, mpgetflt(i)+0.0))
1354 s.Fatalf("bad float size %d", n.Type.Size())
1359 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
1366 // Assume everything will work out, so set up our return value.
1367 // Anything interesting that happens from here is a fatal.
1370 // Special case for not confusing GC and liveness.
1371 // We don't want pointers accidentally classified
1372 // as not-pointers or vice-versa because of copy
1374 if to.IsPtr() != from.IsPtr() {
1375 return s.newValue2(ssa.OpConvert, to, x, s.mem())
1378 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1381 if to.Etype == TFUNC && from.IsPtr() {
1385 // named <--> unnamed type or typed <--> untyped const
1386 if from.Etype == to.Etype {
1390 // unsafe.Pointer <--> *T
1391 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1397 if from.Width != to.Width {
1398 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1401 if etypesign(from.Etype) != etypesign(to.Etype) {
1402 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
1407 // These appear to be fine, but they fail the
1408 // integer constraint below, so okay them here.
1409 // Sample non-integer conversion: map[string]string -> *uint8
1413 if etypesign(from.Etype) == 0 {
1414 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1418 // integer, same width, same sign
1423 ft := n.Left.Type // from type
1424 tt := n.Type // to type
1425 if ft.IsInteger() && tt.IsInteger() {
1427 if tt.Size() == ft.Size() {
1429 } else if tt.Size() < ft.Size() {
1431 switch 10*ft.Size() + tt.Size() {
1433 op = ssa.OpTrunc16to8
1435 op = ssa.OpTrunc32to8
1437 op = ssa.OpTrunc32to16
1439 op = ssa.OpTrunc64to8
1441 op = ssa.OpTrunc64to16
1443 op = ssa.OpTrunc64to32
1445 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1447 } else if ft.IsSigned() {
1449 switch 10*ft.Size() + tt.Size() {
1451 op = ssa.OpSignExt8to16
1453 op = ssa.OpSignExt8to32
1455 op = ssa.OpSignExt8to64
1457 op = ssa.OpSignExt16to32
1459 op = ssa.OpSignExt16to64
1461 op = ssa.OpSignExt32to64
1463 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1467 switch 10*ft.Size() + tt.Size() {
1469 op = ssa.OpZeroExt8to16
1471 op = ssa.OpZeroExt8to32
1473 op = ssa.OpZeroExt8to64
1475 op = ssa.OpZeroExt16to32
1477 op = ssa.OpZeroExt16to64
1479 op = ssa.OpZeroExt32to64
1481 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1484 return s.newValue1(op, n.Type, x)
1487 if ft.IsFloat() || tt.IsFloat() {
1488 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1490 s.Fatalf("weird float conversion %s -> %s", ft, tt)
1492 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1494 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1495 // normal case, not tripping over unsigned 64
1496 if op1 == ssa.OpCopy {
1497 if op2 == ssa.OpCopy {
1500 return s.newValue1(op2, n.Type, x)
1502 if op2 == ssa.OpCopy {
1503 return s.newValue1(op1, n.Type, x)
1505 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1507 // Tricky 64-bit unsigned cases.
1509 // therefore tt is float32 or float64, and ft is also unsigned
1511 return s.uint64Tofloat32(n, x, ft, tt)
1514 return s.uint64Tofloat64(n, x, ft, tt)
1516 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
1518 // therefore ft is float32 or float64, and tt is unsigned integer
1520 return s.float32ToUint64(n, x, ft, tt)
1523 return s.float64ToUint64(n, x, ft, tt)
1525 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1529 if ft.IsComplex() && tt.IsComplex() {
1531 if ft.Size() == tt.Size() {
1533 } else if ft.Size() == 8 && tt.Size() == 16 {
1534 op = ssa.OpCvt32Fto64F
1535 } else if ft.Size() == 16 && tt.Size() == 8 {
1536 op = ssa.OpCvt64Fto32F
1538 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1540 ftp := floatForComplex(ft)
1541 ttp := floatForComplex(tt)
1542 return s.newValue2(ssa.OpComplexMake, tt,
1543 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1544 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1547 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
1551 res, _ := s.dottype(n, false)
1555 case OLT, OEQ, ONE, OLE, OGE, OGT:
1557 b := s.expr(n.Right)
1558 if n.Left.Type.IsComplex() {
1559 pt := floatForComplex(n.Left.Type)
1560 op := s.ssaOp(OEQ, pt)
1561 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1562 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1563 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1568 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1570 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1573 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
1576 b := s.expr(n.Right)
1577 if n.Type.IsComplex() {
1578 mulop := ssa.OpMul64F
1579 addop := ssa.OpAdd64F
1580 subop := ssa.OpSub64F
1581 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1582 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1584 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1585 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1586 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1587 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1589 if pt != wt { // Widen for calculation
1590 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1591 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1592 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1593 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1596 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1597 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1599 if pt != wt { // Narrow to store back
1600 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1601 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1604 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1606 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1610 b := s.expr(n.Right)
1611 if n.Type.IsComplex() {
1612 // TODO this is not executed because the front-end substitutes a runtime call.
1613 // That probably ought to change; with modest optimization the widen/narrow
1614 // conversions could all be elided in larger expression trees.
1615 mulop := ssa.OpMul64F
1616 addop := ssa.OpAdd64F
1617 subop := ssa.OpSub64F
1618 divop := ssa.OpDiv64F
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 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1635 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1636 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1638 // TODO not sure if this is best done in wide precision or narrow
1639 // Double-rounding might be an issue.
1640 // Note that the pre-SSA implementation does the entire calculation
1641 // in wide format, so wide is compatible.
1642 xreal = s.newValue2(divop, wt, xreal, denom)
1643 ximag = s.newValue2(divop, wt, ximag, denom)
1645 if pt != wt { // Narrow to store back
1646 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1647 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1649 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1651 if n.Type.IsFloat() {
1652 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1654 // do a size-appropriate check for zero
1655 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1656 s.check(cmp, panicdivide)
1657 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1661 b := s.expr(n.Right)
1662 // do a size-appropriate check for zero
1663 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1664 s.check(cmp, panicdivide)
1665 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1668 b := s.expr(n.Right)
1669 if n.Type.IsComplex() {
1670 pt := floatForComplex(n.Type)
1671 op := s.ssaOp(n.Op, pt)
1672 return s.newValue2(ssa.OpComplexMake, n.Type,
1673 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1674 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1676 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1677 case OAND, OOR, OHMUL, OXOR:
1679 b := s.expr(n.Right)
1680 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1683 b := s.expr(n.Right)
1684 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
1688 if i <= 0 || i >= n.Type.Size()*8 {
1689 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1691 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
1692 case OANDAND, OOROR:
1693 // To implement OANDAND (and OOROR), we introduce a
1694 // new temporary variable to hold the result. The
1695 // variable is associated with the OANDAND node in the
1696 // s.vars table (normally variables are only
1697 // associated with ONAME nodes). We convert
1704 // Using var in the subsequent block introduces the
1705 // necessary phi variable.
1706 el := s.expr(n.Left)
1710 b.Kind = ssa.BlockIf
1712 // In theory, we should set b.Likely here based on context.
1713 // However, gc only gives us likeliness hints
1714 // in a single place, for plain OIF statements,
1715 // and passing around context is finnicky, so don't bother for now.
1717 bRight := s.f.NewBlock(ssa.BlockPlain)
1718 bResult := s.f.NewBlock(ssa.BlockPlain)
1719 if n.Op == OANDAND {
1721 b.AddEdgeTo(bResult)
1722 } else if n.Op == OOROR {
1723 b.AddEdgeTo(bResult)
1727 s.startBlock(bRight)
1728 er := s.expr(n.Right)
1732 b.AddEdgeTo(bResult)
1734 s.startBlock(bResult)
1735 return s.variable(n, Types[TBOOL])
1738 i := s.expr(n.Right)
1739 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
1744 if n.Type.IsComplex() {
1745 tp := floatForComplex(n.Type)
1746 negop := s.ssaOp(n.Op, tp)
1747 return s.newValue2(ssa.OpComplexMake, n.Type,
1748 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1749 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1751 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1752 case ONOT, OCOM, OSQRT:
1754 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1757 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
1759 return s.expr(n.Left)
1762 return s.addr(n.Left, n.Bounded)
1765 if int(n.Reg) != Thearch.REGSP {
1766 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1769 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1770 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1775 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1778 // TODO: fix when we can SSA struct types.
1779 p := s.addr(n, false)
1780 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1785 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
1786 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1790 case n.Left.Type.IsString():
1792 i := s.expr(n.Right)
1793 i = s.extendIndex(i)
1795 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1796 s.boundsCheck(i, len)
1798 ptrtyp := Ptrto(Types[TUINT8])
1799 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1800 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1801 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1802 case n.Left.Type.IsSlice():
1803 p := s.addr(n, false)
1804 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1805 case n.Left.Type.IsArray():
1806 // TODO: fix when we can SSA arrays of length 1.
1807 p := s.addr(n, false)
1808 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1810 s.Fatalf("bad type for index %v", n.Left.Type)
1816 case n.Left.Type.IsSlice():
1817 op := ssa.OpSliceLen
1821 return s.newValue1(op, Types[TINT], s.expr(n.Left))
1822 case n.Left.Type.IsString(): // string; not reachable for OCAP
1823 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
1824 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1825 return s.referenceTypeBuiltin(n, s.expr(n.Left))
1827 return s.constInt(Types[TINT], n.Left.Type.Bound)
1832 if n.Left.Type.IsSlice() {
1833 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1835 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1840 return s.newValue1(ssa.OpITab, n.Type, a)
1843 tab := s.expr(n.Left)
1844 data := s.expr(n.Right)
1845 // The frontend allows putting things like struct{*byte} in
1846 // the data portion of an eface. But we don't want struct{*byte}
1847 // as a register type because (among other reasons) the liveness
1848 // analysis is confused by the "fat" variables that result from
1849 // such types being spilled.
1850 // So here we ensure that we are selecting the underlying pointer
1851 // when we build an eface.
1852 for !data.Type.IsPtr() {
1854 case data.Type.IsArray():
1855 data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
1856 case data.Type.IsStruct():
1857 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1858 f := data.Type.FieldType(i)
1860 // eface type could also be struct{p *byte; q [0]int}
1863 data = s.newValue1I(ssa.OpStructSelect, f, data.Type.FieldOff(i), data)
1867 s.Fatalf("type being put into an eface isn't a pointer")
1870 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1872 case OSLICE, OSLICEARR:
1875 if n.Right.Left != nil {
1876 i = s.extendIndex(s.expr(n.Right.Left))
1878 if n.Right.Right != nil {
1879 j = s.extendIndex(s.expr(n.Right.Right))
1881 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1882 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1886 if n.Right.Left != nil {
1887 i = s.extendIndex(s.expr(n.Right.Left))
1889 if n.Right.Right != nil {
1890 j = s.extendIndex(s.expr(n.Right.Right))
1892 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1893 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1894 case OSLICE3, OSLICE3ARR:
1897 if n.Right.Left != nil {
1898 i = s.extendIndex(s.expr(n.Right.Left))
1900 j := s.extendIndex(s.expr(n.Right.Right.Left))
1901 k := s.extendIndex(s.expr(n.Right.Right.Right))
1902 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1903 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1905 case OCALLFUNC, OCALLINTER, OCALLMETH:
1906 return s.call(n, callNormal)
1909 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
1912 // append(s, e1, e2, e3). Compile like:
1914 // newlen := len + 3
1915 // if newlen > s.cap {
1916 // ptr,_,cap = growslice(s, newlen)
1919 // *(ptr+len+1) = e2
1920 // *(ptr+len+2) = e3
1921 // makeslice(ptr,newlen,cap)
1927 slice := s.expr(n.List.N)
1929 // Allocate new blocks
1930 grow := s.f.NewBlock(ssa.BlockPlain)
1931 assign := s.f.NewBlock(ssa.BlockPlain)
1933 // Decide if we need to grow
1934 nargs := int64(count(n.List) - 1)
1935 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
1936 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
1937 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
1938 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
1939 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
1943 b.Kind = ssa.BlockIf
1944 b.Likely = ssa.BranchUnlikely
1951 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
1953 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
1955 s.vars[&ptrVar] = r[0]
1956 // Note: we don't need to read r[1], the result's length. It will be nl.
1957 // (or maybe we should, we just have to spill/restore nl otherwise?)
1958 s.vars[&capVar] = r[2]
1962 // assign new elements to slots
1963 s.startBlock(assign)
1966 args := make([]*ssa.Value, 0, nargs)
1967 store := make([]bool, 0, nargs)
1968 for l := n.List.Next; l != nil; l = l.Next {
1969 if canSSAType(l.N.Type) {
1970 args = append(args, s.expr(l.N))
1971 store = append(store, true)
1973 args = append(args, s.addr(l.N, false))
1974 store = append(store, false)
1978 p = s.variable(&ptrVar, pt) // generates phi for ptr
1979 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
1980 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
1981 for i, arg := range args {
1982 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
1984 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
1986 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
1988 if haspointers(et) {
1989 // TODO: just one write barrier call for all of these writes?
1990 // TODO: maybe just one writeBarrier.enabled check?
1991 s.insertWB(et, addr, n.Lineno)
1996 delete(s.vars, &ptrVar)
1997 delete(s.vars, &capVar)
1998 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2001 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
2006 // condBranch evaluates the boolean expression cond and branches to yes
2007 // if cond is true and no if cond is false.
2008 // This function is intended to handle && and || better than just calling
2009 // s.expr(cond) and branching on the result.
2010 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2011 if cond.Op == OANDAND {
2012 mid := s.f.NewBlock(ssa.BlockPlain)
2013 s.stmtList(cond.Ninit)
2014 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2016 s.condBranch(cond.Right, yes, no, likely)
2018 // Note: if likely==1, then both recursive calls pass 1.
2019 // If likely==-1, then we don't have enough information to decide
2020 // whether the first branch is likely or not. So we pass 0 for
2021 // the likeliness of the first branch.
2022 // TODO: have the frontend give us branch prediction hints for
2023 // OANDAND and OOROR nodes (if it ever has such info).
2025 if cond.Op == OOROR {
2026 mid := s.f.NewBlock(ssa.BlockPlain)
2027 s.stmtList(cond.Ninit)
2028 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2030 s.condBranch(cond.Right, yes, no, likely)
2032 // Note: if likely==-1, then both recursive calls pass -1.
2033 // If likely==1, then we don't have enough info to decide
2034 // the likelihood of the first branch.
2036 if cond.Op == ONOT {
2037 s.stmtList(cond.Ninit)
2038 s.condBranch(cond.Left, no, yes, -likely)
2043 b.Kind = ssa.BlockIf
2045 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2050 func (s *state) assign(left *Node, right *ssa.Value, wb bool) {
2051 if left.Op == ONAME && isblank(left) {
2057 // right == nil means use the zero value of the assigned type.
2059 // if we can't ssa this memory, treat it as just zeroing out the backing memory
2060 addr := s.addr(left, false)
2061 if left.Op == ONAME {
2062 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2064 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2067 right = s.zeroVal(t)
2069 if left.Op == ONAME && canSSA(left) {
2070 // Update variable assignment.
2071 s.vars[left] = right
2072 s.addNamedValue(left, right)
2075 // not ssa-able. Treat as a store.
2076 addr := s.addr(left, false)
2077 if left.Op == ONAME {
2078 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2080 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
2082 s.insertWB(left.Type, addr, left.Lineno)
2086 // zeroVal returns the zero value for type t.
2087 func (s *state) zeroVal(t *Type) *ssa.Value {
2092 return s.constInt8(t, 0)
2094 return s.constInt16(t, 0)
2096 return s.constInt32(t, 0)
2098 return s.constInt64(t, 0)
2100 s.Fatalf("bad sized integer type %s", t)
2105 return s.constFloat32(t, 0)
2107 return s.constFloat64(t, 0)
2109 s.Fatalf("bad sized float type %s", t)
2114 z := s.constFloat32(Types[TFLOAT32], 0)
2115 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2117 z := s.constFloat64(Types[TFLOAT64], 0)
2118 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2120 s.Fatalf("bad sized complex type %s", t)
2124 return s.entryNewValue0A(ssa.OpConstString, t, "")
2126 return s.entryNewValue0(ssa.OpConstNil, t)
2128 return s.constBool(false)
2129 case t.IsInterface():
2130 return s.entryNewValue0(ssa.OpConstInterface, t)
2132 return s.entryNewValue0(ssa.OpConstSlice, t)
2134 s.Unimplementedf("zero for type %v not implemented", t)
2141 callNormal callKind = iota
2146 func (s *state) call(n *Node, k callKind) *ssa.Value {
2147 var sym *Sym // target symbol (if static)
2148 var closure *ssa.Value // ptr to closure to run (if dynamic)
2149 var codeptr *ssa.Value // ptr to target code (if dynamic)
2150 var rcvr *ssa.Value // receiver to set
2154 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2158 closure = s.expr(fn)
2160 return nil // TODO: remove when expr always returns non-nil
2163 if fn.Op != ODOTMETH {
2164 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2166 if fn.Right.Op != ONAME {
2167 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2169 if k == callNormal {
2175 closure = s.expr(&n2)
2176 // Note: receiver is already assigned in n.List, so we don't
2177 // want to set it here.
2179 if fn.Op != ODOTINTER {
2180 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2182 i := s.expr(fn.Left)
2183 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2184 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2185 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2186 if k == callNormal {
2187 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2191 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2194 stksize := fn.Type.Argwid // includes receiver
2196 // Run all argument assignments. The arg slots have already
2197 // been offset by the appropriate amount (+2*widthptr for go/defer,
2198 // +widthptr for interface calls).
2199 // For OCALLMETH, the receiver is set in these statements.
2202 // Set receiver (for interface calls)
2204 argStart := Ctxt.FixedFrameSize()
2205 if k != callNormal {
2206 argStart += int64(2 * Widthptr)
2208 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
2209 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
2213 if k != callNormal {
2214 // Write argsize and closure (args to Newproc/Deferproc).
2215 argsize := s.constInt32(Types[TUINT32], int32(stksize))
2216 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
2217 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
2218 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
2219 stksize += 2 * int64(Widthptr)
2223 bNext := s.f.NewBlock(ssa.BlockPlain)
2226 case k == callDefer:
2227 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2229 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2230 case closure != nil:
2231 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2232 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2233 case codeptr != nil:
2234 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2236 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2238 Fatalf("bad call type %s %v", opnames[n.Op], n)
2240 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2242 // Finish call block
2243 s.vars[&memVar] = call
2245 b.Kind = ssa.BlockCall
2249 // Read result from stack at the start of the fallthrough block
2252 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2253 if fp == nil || k != callNormal {
2254 // call has no return value. Continue with the next statement.
2257 a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
2258 return s.newValue2(ssa.OpLoad, fp.Type, a, call)
2261 // etypesign returns the signed-ness of e, for integer/pointer etypes.
2262 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
2263 func etypesign(e EType) int8 {
2265 case TINT8, TINT16, TINT32, TINT64, TINT:
2267 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2273 // lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2274 // This improves the effectiveness of cse by using the same Aux values for the
2276 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2279 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2280 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2281 // these are the only valid types
2284 if lsym, ok := s.varsyms[n]; ok {
2292 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
2293 // The value that the returned Value represents is guaranteed to be non-nil.
2294 // If bounded is true then this address does not require a nil check for its operand
2295 // even if that would otherwise be implied.
2296 func (s *state) addr(n *Node, bounded bool) *ssa.Value {
2303 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
2304 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
2305 // TODO: Make OpAddr use AuxInt as well as Aux.
2307 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2316 if n.String() == ".fp" {
2317 // Special arg that points to the frame pointer.
2318 // (Used by the race detector, others?)
2319 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2320 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2322 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2325 // We need to regenerate the address of autos
2326 // at every use. This prevents LEA instructions
2327 // from occurring before the corresponding VarDef
2328 // op and confusing the liveness analysis into thinking
2329 // the variable is live at function entry.
2330 // TODO: I'm not sure if this really works or we're just
2331 // getting lucky. We might need a real dependency edge
2332 // between vardef and addr ops.
2333 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
2334 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2335 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
2336 // ensure that we reuse symbols for out parameters so
2337 // that cse works on their addresses
2338 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2339 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2340 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
2341 return s.expr(n.Name.Heapaddr)
2343 s.Unimplementedf("variable address class %v not implemented", n.Class)
2347 // indirect off a register
2348 // used for storing/loading arguments/returns to/from callees
2349 if int(n.Reg) != Thearch.REGSP {
2350 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2353 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
2355 if n.Left.Type.IsSlice() {
2357 i := s.expr(n.Right)
2358 i = s.extendIndex(i)
2359 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
2361 s.boundsCheck(i, len)
2363 p := s.newValue1(ssa.OpSlicePtr, t, a)
2364 return s.newValue2(ssa.OpPtrIndex, t, p, i)
2366 a := s.addr(n.Left, bounded)
2367 i := s.expr(n.Right)
2368 i = s.extendIndex(i)
2369 len := s.constInt(Types[TINT], n.Left.Type.Bound)
2371 s.boundsCheck(i, len)
2373 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
2382 p := s.addr(n.Left, bounded)
2383 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2389 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2391 return s.newValue2(ssa.OpAddPtr, t,
2392 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
2393 s.constInt(Types[TINT], n.Xoffset))
2396 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2397 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2400 // Recover original offset to address passed-in param value.
2402 original_p.Xoffset = n.Xoffset
2403 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
2404 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2406 addr := s.addr(n.Left, bounded)
2407 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
2410 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
2415 // canSSA reports whether n is SSA-able.
2416 // n must be an ONAME.
2417 func canSSA(n *Node) bool {
2424 if n.Class&PHEAP != 0 {
2428 case PEXTERN, PPARAMOUT, PPARAMREF:
2431 if n.Class == PPARAM && n.String() == ".this" {
2432 // wrappers generated by genwrapper need to update
2433 // the .this pointer in place.
2436 return canSSAType(n.Type)
2437 // TODO: try to make more variables SSAable?
2440 // canSSA reports whether variables of type t are SSA-able.
2441 func canSSAType(t *Type) bool {
2443 if t.Width > int64(4*Widthptr) {
2444 // 4*Widthptr is an arbitrary constant. We want it
2445 // to be at least 3*Widthptr so slices can be registerized.
2446 // Too big and we'll introduce too much register pressure.
2454 // We can't do arrays because dynamic indexing is
2455 // not supported on SSA variables.
2456 // TODO: maybe allow if length is <=1? All indexes
2457 // are constant? Might be good for the arrays
2458 // introduced by the compiler for variadic functions.
2461 if countfield(t) > 4 {
2462 // 4 is an arbitrary constant. Same reasoning
2463 // as above, lots of small fields would waste
2464 // register space needed by other values.
2467 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2468 if !canSSAType(t1.Type) {
2472 return false // until it is implemented
2479 // nilCheck generates nil pointer checking code.
2480 // Starts a new block on return, unless nil checks are disabled.
2481 // Used only for automatically inserted nil checks,
2482 // not for user code like 'x != nil'.
2483 func (s *state) nilCheck(ptr *ssa.Value) {
2484 if Disable_checknil != 0 {
2487 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
2489 b.Kind = ssa.BlockCheck
2491 bNext := s.f.NewBlock(ssa.BlockPlain)
2496 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2497 // Starts a new block on return.
2498 func (s *state) boundsCheck(idx, len *ssa.Value) {
2499 if Debug['B'] != 0 {
2502 // TODO: convert index to full width?
2503 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2506 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
2507 s.check(cmp, Panicindex)
2510 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2511 // Starts a new block on return.
2512 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2513 if Debug['B'] != 0 {
2516 // TODO: convert index to full width?
2517 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2520 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
2521 s.check(cmp, panicslice)
2524 // If cmp (a bool) is true, panic using the given function.
2525 func (s *state) check(cmp *ssa.Value, fn *Node) {
2527 b.Kind = ssa.BlockIf
2529 b.Likely = ssa.BranchLikely
2530 bNext := s.f.NewBlock(ssa.BlockPlain)
2531 line := s.peekLine()
2532 bPanic := s.panics[funcLine{fn, line}]
2534 bPanic = s.f.NewBlock(ssa.BlockPlain)
2535 s.panics[funcLine{fn, line}] = bPanic
2536 s.startBlock(bPanic)
2537 // The panic call takes/returns memory to ensure that the right
2538 // memory state is observed if the panic happens.
2539 s.rtcall(fn, false, nil)
2546 // rtcall issues a call to the given runtime function fn with the listed args.
2547 // Returns a slice of results of the given result types.
2548 // The call is added to the end of the current block.
2549 // If returns is false, the block is marked as an exit block.
2550 // If returns is true, the block is marked as a call block. A new block
2551 // is started to load the return values.
2552 func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2553 // Write args to the stack
2554 var off int64 // TODO: arch-dependent starting offset?
2555 for _, arg := range args {
2557 off = Rnd(off, t.Alignment())
2560 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2563 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2566 off = Rnd(off, int64(Widthptr))
2569 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2570 s.vars[&memVar] = call
2575 b.Kind = ssa.BlockExit
2578 if len(results) > 0 {
2579 Fatalf("panic call can't have results")
2583 b.Kind = ssa.BlockCall
2585 bNext := s.f.NewBlock(ssa.BlockPlain)
2590 res := make([]*ssa.Value, len(results))
2591 for i, t := range results {
2592 off = Rnd(off, t.Alignment())
2595 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2597 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2600 off = Rnd(off, int64(Widthptr))
2602 // Remember how much callee stack space we needed.
2608 // insertWB inserts a write barrier. A value of type t has already
2609 // been stored at location p. Tell the runtime about this write.
2610 // Note: there must be no GC suspension points between the write and
2611 // the call that this function inserts.
2612 func (s *state) insertWB(t *Type, p *ssa.Value, line int32) {
2613 // if writeBarrier.enabled {
2614 // typedmemmove_nostore(&t, p)
2616 bThen := s.f.NewBlock(ssa.BlockPlain)
2618 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2619 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2620 // TODO: select the .enabled field. It is currently first, so not needed for now.
2621 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2623 b.Kind = ssa.BlockIf
2624 b.Likely = ssa.BranchUnlikely
2629 // TODO: writebarrierptr_nostore if just one pointer word (or a few?)
2630 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
2631 s.rtcall(typedmemmove_nostore, true, nil, taddr, p)
2634 Warnl(int(line), "write barrier")
2637 b.AddEdgeTo(s.curBlock)
2640 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2641 // i,j,k may be nil, in which case they are set to their default value.
2642 // t is a slice, ptr to array, or string type.
2643 func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2649 zero := s.constInt(Types[TINT], 0)
2653 ptrtype = Ptrto(elemtype)
2654 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2655 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2656 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2658 elemtype = Types[TUINT8]
2659 ptrtype = Ptrto(elemtype)
2660 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2661 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2664 if !t.Type.IsArray() {
2665 s.Fatalf("bad ptr to array in slice %v\n", t)
2667 elemtype = t.Type.Type
2668 ptrtype = Ptrto(elemtype)
2671 len = s.constInt(Types[TINT], t.Type.Bound)
2674 s.Fatalf("bad type in slice %v\n", t)
2677 // Set default values
2688 // Panic if slice indices are not in bounds.
2689 s.sliceBoundsCheck(i, j)
2691 s.sliceBoundsCheck(j, k)
2694 s.sliceBoundsCheck(k, cap)
2697 // Generate the following code assuming that indexes are in bounds.
2698 // The conditional is to make sure that we don't generate a slice
2699 // that points to the next object in memory.
2700 // rlen = (Sub64 j i)
2701 // rcap = (Sub64 k i)
2704 // p = (AddPtr ptr (Mul64 low (Const64 size)))
2706 // result = (SliceMake p size)
2707 subOp := s.ssaOp(OSUB, Types[TINT])
2708 neqOp := s.ssaOp(ONE, Types[TINT])
2709 mulOp := s.ssaOp(OMUL, Types[TINT])
2710 rlen := s.newValue2(subOp, Types[TINT], j, i)
2714 // Capacity of the result is unimportant. However, we use
2715 // rcap to test if we've generated a zero-length slice.
2716 // Use length of strings for that.
2721 rcap = s.newValue2(subOp, Types[TINT], k, i)
2724 s.vars[&ptrVar] = ptr
2726 // Generate code to test the resulting slice length.
2727 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
2730 b.Kind = ssa.BlockIf
2731 b.Likely = ssa.BranchLikely
2734 // Generate code for non-zero length slice case.
2735 nz := s.f.NewBlock(ssa.BlockPlain)
2739 if elemtype.Width == 1 {
2742 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
2744 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
2748 merge := s.f.NewBlock(ssa.BlockPlain)
2752 rptr := s.variable(&ptrVar, ptrtype)
2753 delete(s.vars, &ptrVar)
2754 return rptr, rlen, rcap
2757 type u2fcvtTab struct {
2758 geq, cvt2F, and, rsh, or, add ssa.Op
2759 one func(*state, ssa.Type, int64) *ssa.Value
2762 var u64_f64 u2fcvtTab = u2fcvtTab{
2764 cvt2F: ssa.OpCvt64to64F,
2766 rsh: ssa.OpRsh64Ux64,
2769 one: (*state).constInt64,
2772 var u64_f32 u2fcvtTab = u2fcvtTab{
2774 cvt2F: ssa.OpCvt64to32F,
2776 rsh: ssa.OpRsh64Ux64,
2779 one: (*state).constInt64,
2782 // Excess generality on a machine with 64-bit integer registers.
2783 // Not used on AMD64.
2784 var u32_f32 u2fcvtTab = u2fcvtTab{
2786 cvt2F: ssa.OpCvt32to32F,
2788 rsh: ssa.OpRsh32Ux32,
2791 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
2792 return s.constInt32(t, int32(x))
2796 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2797 return s.uintTofloat(&u64_f64, n, x, ft, tt)
2800 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2801 return s.uintTofloat(&u64_f32, n, x, ft, tt)
2804 func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2806 // result = (floatY) x
2808 // y = uintX(x) ; y = x & 1
2809 // z = uintX(x) ; z = z >> 1
2812 // result = floatY(z)
2813 // result = result + result
2816 // Code borrowed from old code generator.
2817 // What's going on: large 64-bit "unsigned" looks like
2818 // negative number to hardware's integer-to-float
2819 // conversion. However, because the mantissa is only
2820 // 63 bits, we don't need the LSB, so instead we do an
2821 // unsigned right shift (divide by two), convert, and
2822 // double. However, before we do that, we need to be
2823 // sure that we do not lose a "1" if that made the
2824 // difference in the resulting rounding. Therefore, we
2825 // preserve it, and OR (not ADD) it back in. The case
2826 // that matters is when the eleven discarded bits are
2827 // equal to 10000000001; that rounds up, and the 1 cannot
2828 // be lost else it would round down if the LSB of the
2829 // candidate mantissa is 0.
2830 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
2832 b.Kind = ssa.BlockIf
2834 b.Likely = ssa.BranchLikely
2836 bThen := s.f.NewBlock(ssa.BlockPlain)
2837 bElse := s.f.NewBlock(ssa.BlockPlain)
2838 bAfter := s.f.NewBlock(ssa.BlockPlain)
2842 a0 := s.newValue1(cvttab.cvt2F, tt, x)
2845 bThen.AddEdgeTo(bAfter)
2849 one := cvttab.one(s, ft, 1)
2850 y := s.newValue2(cvttab.and, ft, x, one)
2851 z := s.newValue2(cvttab.rsh, ft, x, one)
2852 z = s.newValue2(cvttab.or, ft, z, y)
2853 a := s.newValue1(cvttab.cvt2F, tt, z)
2854 a1 := s.newValue2(cvttab.add, tt, a, a)
2857 bElse.AddEdgeTo(bAfter)
2859 s.startBlock(bAfter)
2860 return s.variable(n, n.Type)
2863 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
2864 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
2865 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
2866 s.Fatalf("node must be a map or a channel")
2872 // return *((*int)n)
2874 // return *(((*int)n)+1)
2877 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
2878 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
2880 b.Kind = ssa.BlockIf
2882 b.Likely = ssa.BranchUnlikely
2884 bThen := s.f.NewBlock(ssa.BlockPlain)
2885 bElse := s.f.NewBlock(ssa.BlockPlain)
2886 bAfter := s.f.NewBlock(ssa.BlockPlain)
2888 // length/capacity of a nil map/chan is zero
2891 s.vars[n] = s.zeroVal(lenType)
2893 bThen.AddEdgeTo(bAfter)
2898 // length is stored in the first word for map/chan
2899 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
2900 } else if n.Op == OCAP {
2901 // capacity is stored in the second word for chan
2902 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
2903 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
2905 s.Fatalf("op must be OLEN or OCAP")
2908 bElse.AddEdgeTo(bAfter)
2910 s.startBlock(bAfter)
2911 return s.variable(n, lenType)
2914 type f2uCvtTab struct {
2915 ltf, cvt2U, subf ssa.Op
2916 value func(*state, ssa.Type, float64) *ssa.Value
2919 var f32_u64 f2uCvtTab = f2uCvtTab{
2921 cvt2U: ssa.OpCvt32Fto64,
2923 value: (*state).constFloat32,
2926 var f64_u64 f2uCvtTab = f2uCvtTab{
2928 cvt2U: ssa.OpCvt64Fto64,
2930 value: (*state).constFloat64,
2933 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2934 return s.floatToUint(&f32_u64, n, x, ft, tt)
2936 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2937 return s.floatToUint(&f64_u64, n, x, ft, tt)
2940 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2941 // if x < 9223372036854775808.0 {
2942 // result = uintY(x)
2944 // y = x - 9223372036854775808.0
2946 // result = z | -9223372036854775808
2948 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
2949 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
2951 b.Kind = ssa.BlockIf
2953 b.Likely = ssa.BranchLikely
2955 bThen := s.f.NewBlock(ssa.BlockPlain)
2956 bElse := s.f.NewBlock(ssa.BlockPlain)
2957 bAfter := s.f.NewBlock(ssa.BlockPlain)
2961 a0 := s.newValue1(cvttab.cvt2U, tt, x)
2964 bThen.AddEdgeTo(bAfter)
2968 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
2969 y = s.newValue1(cvttab.cvt2U, tt, y)
2970 z := s.constInt64(tt, -9223372036854775808)
2971 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
2974 bElse.AddEdgeTo(bAfter)
2976 s.startBlock(bAfter)
2977 return s.variable(n, n.Type)
2980 // ifaceType returns the value for the word containing the type.
2981 // n is the node for the interface expression.
2982 // v is the corresponding value.
2983 func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
2984 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
2986 if isnilinter(n.Type) {
2987 // Have *eface. The type is the first word in the struct.
2988 return s.newValue1(ssa.OpITab, byteptr, v)
2992 // The first word in the struct is the *itab.
2993 // If the *itab is nil, return 0.
2994 // Otherwise, the second word in the *itab is the type.
2996 tab := s.newValue1(ssa.OpITab, byteptr, v)
2997 s.vars[&typVar] = tab
2998 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3000 b.Kind = ssa.BlockIf
3001 b.Control = isnonnil
3002 b.Likely = ssa.BranchLikely
3004 bLoad := s.f.NewBlock(ssa.BlockPlain)
3005 bEnd := s.f.NewBlock(ssa.BlockPlain)
3009 bLoad.AddEdgeTo(bEnd)
3012 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3013 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3017 typ := s.variable(&typVar, byteptr)
3018 delete(s.vars, &typVar)
3022 // dottype generates SSA for a type assertion node.
3023 // commaok indicates whether to panic or return a bool.
3024 // If commaok is false, resok will be nil.
3025 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3026 iface := s.expr(n.Left)
3027 typ := s.ifaceType(n.Left, iface) // actual concrete type
3028 target := s.expr(typename(n.Type)) // target type
3029 if !isdirectiface(n.Type) {
3030 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3031 Fatalf("dottype needs a direct iface type %s", n.Type)
3034 if Debug_typeassert > 0 {
3035 Warnl(int(n.Lineno), "type assertion inlined")
3038 // TODO: If we have a nonempty interface and its itab field is nil,
3039 // then this test is redundant and ifaceType should just branch directly to bFail.
3040 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3042 b.Kind = ssa.BlockIf
3044 b.Likely = ssa.BranchLikely
3046 byteptr := Ptrto(Types[TUINT8])
3048 bOk := s.f.NewBlock(ssa.BlockPlain)
3049 bFail := s.f.NewBlock(ssa.BlockPlain)
3054 // on failure, panic by calling panicdottype
3056 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
3057 s.rtcall(panicdottype, false, nil, typ, target, taddr)
3059 // on success, return idata field
3061 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3064 // commaok is the more complicated case because we have
3065 // a control flow merge point.
3066 bEnd := s.f.NewBlock(ssa.BlockPlain)
3068 // type assertion succeeded
3070 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3071 s.vars[&okVar] = s.constBool(true)
3075 // type assertion failed
3077 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3078 s.vars[&okVar] = s.constBool(false)
3080 bFail.AddEdgeTo(bEnd)
3084 res = s.variable(&idataVar, byteptr)
3085 resok = s.variable(&okVar, Types[TBOOL])
3086 delete(s.vars, &idataVar)
3087 delete(s.vars, &okVar)
3091 // checkgoto checks that a goto from from to to does not
3092 // jump into a block or jump over variable declarations.
3093 // It is a copy of checkgoto in the pre-SSA backend,
3094 // modified only for line number handling.
3095 // TODO: document how this works and why it is designed the way it is.
3096 func (s *state) checkgoto(from *Node, to *Node) {
3097 if from.Sym == to.Sym {
3102 for fs := from.Sym; fs != nil; fs = fs.Link {
3106 for fs := to.Sym; fs != nil; fs = fs.Link {
3110 for ; nf > nt; nf-- {
3114 // decide what to complain about.
3115 // prefer to complain about 'into block' over declarations,
3116 // so scan backward to find most recent block or else dcl.
3121 for ; nt > nf; nt-- {
3140 lno := int(from.Left.Lineno)
3142 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
3144 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
3149 // variable returns the value of a variable at the current location.
3150 func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
3153 // TODO: get type? Take Sym as arg?
3154 v = s.newValue0A(ssa.OpFwdRef, t, name)
3160 func (s *state) mem() *ssa.Value {
3161 return s.variable(&memVar, ssa.TypeMem)
3164 func (s *state) linkForwardReferences() {
3165 // Build ssa graph. Each variable on its first use in a basic block
3166 // leaves a FwdRef in that block representing the incoming value
3167 // of that variable. This function links that ref up with possible definitions,
3168 // inserting Phi values as needed. This is essentially the algorithm
3169 // described by Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3170 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3171 for _, b := range s.f.Blocks {
3172 for _, v := range b.Values {
3173 if v.Op != ssa.OpFwdRef {
3176 name := v.Aux.(*Node)
3179 v.SetArgs1(s.lookupVarIncoming(b, v.Type, name))
3184 // lookupVarIncoming finds the variable's value at the start of block b.
3185 func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
3186 // TODO(khr): have lookupVarIncoming overwrite the fwdRef or copy it
3187 // will be used in, instead of having the result used in a copy value.
3189 if name == &memVar {
3193 v := s.entryNewValue0A(ssa.OpArg, t, name)
3194 // v starts with AuxInt == 0.
3195 s.addNamedValue(name, v)
3198 // variable is live at the entry block. Load it.
3199 addr := s.decladdrs[name]
3201 // TODO: closure args reach here.
3202 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
3204 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3205 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3207 return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem)
3209 var vals []*ssa.Value
3210 for _, p := range b.Preds {
3211 vals = append(vals, s.lookupVarOutgoing(p, t, name))
3214 // This block is dead; we have no predecessors and we're not the entry block.
3215 // It doesn't matter what we use here as long as it is well-formed,
3216 // so use the default/zero value.
3217 if name == &memVar {
3220 return s.zeroVal(name.Type)
3223 for i := 1; i < len(vals); i++ {
3226 v := b.NewValue0(s.peekLine(), ssa.OpPhi, t)
3228 s.addNamedValue(name, v)
3235 // lookupVarOutgoing finds the variable's value at the end of block b.
3236 func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
3237 m := s.defvars[b.ID]
3238 if v, ok := m[name]; ok {
3241 // The variable is not defined by b and we haven't
3242 // looked it up yet. Generate v, a copy value which
3243 // will be the outgoing value of the variable. Then
3244 // look up w, the incoming value of the variable.
3245 // Make v = copy(w). We need the extra copy to
3246 // prevent infinite recursion when looking up the
3247 // incoming value of the variable.
3248 v := b.NewValue0(s.peekLine(), ssa.OpCopy, t)
3250 v.AddArg(s.lookupVarIncoming(b, t, name))
3254 // TODO: the above mutually recursive functions can lead to very deep stacks. Fix that.
3256 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3257 if n.Class == Pxxx {
3258 // Don't track our dummy nodes (&memVar etc.).
3262 // TODO: What the heck is this?
3265 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3266 // Don't track autotmp_ variables.
3269 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3270 // TODO: can't handle auto compound objects with pointers yet.
3271 // The live variable analysis barfs because we don't put VARDEF
3272 // pseudos in the right place when we spill to these nodes.
3275 if n.Class == PAUTO && n.Xoffset != 0 {
3276 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3278 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3279 values, ok := s.f.NamedValues[loc]
3281 s.f.Names = append(s.f.Names, loc)
3283 s.f.NamedValues[loc] = append(values, v)
3286 // an unresolved branch
3287 type branch struct {
3288 p *obj.Prog // branch instruction
3289 b *ssa.Block // target
3292 type genState struct {
3293 // branches remembers all the branch instructions we've seen
3294 // and where they would like to go.
3297 // bstart remembers where each block starts (indexed by block ID)
3300 // deferBranches remembers all the defer branches we've seen.
3301 deferBranches []*obj.Prog
3303 // deferTarget remembers the (last) deferreturn call site.
3304 deferTarget *obj.Prog
3307 // genssa appends entries to ptxt for each instruction in f.
3308 // gcargs and gclocals are filled in with pointer maps for the frame.
3309 func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3312 e := f.Config.Frontend().(*ssaExport)
3313 // We're about to emit a bunch of Progs.
3314 // Since the only way to get here is to explicitly request it,
3315 // just fail on unimplemented instead of trying to unwind our mess.
3316 e.mustImplement = true
3318 // Remember where each block starts.
3319 s.bstart = make([]*obj.Prog, f.NumBlocks())
3321 var valueProgs map[*obj.Prog]*ssa.Value
3322 var blockProgs map[*obj.Prog]*ssa.Block
3323 const logProgs = true
3325 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3326 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3327 f.Logf("genssa %s\n", f.Name)
3328 blockProgs[Pc] = f.Blocks[0]
3331 // Emit basic blocks
3332 for i, b := range f.Blocks {
3334 // Emit values in block
3335 for _, v := range b.Values {
3339 for ; x != Pc; x = x.Link {
3344 // Emit control flow instructions for block
3346 if i < len(f.Blocks)-1 {
3347 next = f.Blocks[i+1]
3352 for ; x != Pc; x = x.Link {
3359 for _, br := range s.branches {
3360 br.p.To.Val = s.bstart[br.b.ID]
3362 if s.deferBranches != nil && s.deferTarget == nil {
3363 // This can happen when the function has a defer but
3364 // no return (because it has an infinite loop).
3368 for _, p := range s.deferBranches {
3369 p.To.Val = s.deferTarget
3373 for p := ptxt; p != nil; p = p.Link {
3375 if v, ok := valueProgs[p]; ok {
3377 } else if b, ok := blockProgs[p]; ok {
3380 s = " " // most value and branch strings are 2-3 characters long
3382 f.Logf("%s\t%s\n", s, p)
3384 if f.Config.HTML != nil {
3385 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3386 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3387 var buf bytes.Buffer
3388 buf.WriteString("<code>")
3389 buf.WriteString("<dl class=\"ssa-gen\">")
3390 for p := ptxt; p != nil; p = p.Link {
3391 buf.WriteString("<dt class=\"ssa-prog-src\">")
3392 if v, ok := valueProgs[p]; ok {
3393 buf.WriteString(v.HTML())
3394 } else if b, ok := blockProgs[p]; ok {
3395 buf.WriteString(b.HTML())
3397 buf.WriteString("</dt>")
3398 buf.WriteString("<dd class=\"ssa-prog\">")
3399 buf.WriteString(html.EscapeString(p.String()))
3400 buf.WriteString("</dd>")
3401 buf.WriteString("</li>")
3403 buf.WriteString("</dl>")
3404 buf.WriteString("</code>")
3405 f.Config.HTML.WriteColumn("genssa", buf.String())
3406 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3411 if f.StaticData != nil {
3412 for _, n := range f.StaticData.([]*Node) {
3413 if !gen_as_init(n, false) {
3414 Fatalf("non-static data marked as static: %v\n\n", n, f)
3419 // Allocate stack frame
3422 // Generate gc bitmaps.
3423 liveness(Curfn, ptxt, gcargs, gclocals)
3427 // Add frame prologue. Zero ambiguously live variables.
3428 Thearch.Defframe(ptxt)
3429 if Debug['f'] != 0 {
3433 // Remove leftover instrumentation from the instruction stream.
3436 f.Config.HTML.Close()
3439 // opregreg emits instructions for
3440 // dest := dest(To) op src(From)
3441 // and also returns the created obj.Prog so it
3442 // may be further adjusted (offset, scale, etc).
3443 func opregreg(op int, dest, src int16) *obj.Prog {
3445 p.From.Type = obj.TYPE_REG
3446 p.To.Type = obj.TYPE_REG
3452 func (s *genState) genValue(v *ssa.Value) {
3455 case ssa.OpAMD64ADDQ:
3456 // TODO: use addq instead of leaq if target is in the right register.
3457 p := Prog(x86.ALEAQ)
3458 p.From.Type = obj.TYPE_MEM
3459 p.From.Reg = regnum(v.Args[0])
3461 p.From.Index = regnum(v.Args[1])
3462 p.To.Type = obj.TYPE_REG
3463 p.To.Reg = regnum(v)
3464 case ssa.OpAMD64ADDL:
3465 p := Prog(x86.ALEAL)
3466 p.From.Type = obj.TYPE_MEM
3467 p.From.Reg = regnum(v.Args[0])
3469 p.From.Index = regnum(v.Args[1])
3470 p.To.Type = obj.TYPE_REG
3471 p.To.Reg = regnum(v)
3472 case ssa.OpAMD64ADDW:
3473 p := Prog(x86.ALEAW)
3474 p.From.Type = obj.TYPE_MEM
3475 p.From.Reg = regnum(v.Args[0])
3477 p.From.Index = regnum(v.Args[1])
3478 p.To.Type = obj.TYPE_REG
3479 p.To.Reg = regnum(v)
3480 // 2-address opcode arithmetic, symmetric
3481 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
3482 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
3483 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3484 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
3485 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
3486 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
3488 x := regnum(v.Args[0])
3489 y := regnum(v.Args[1])
3490 if x != r && y != r {
3491 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3494 p := Prog(v.Op.Asm())
3495 p.From.Type = obj.TYPE_REG
3496 p.To.Type = obj.TYPE_REG
3503 // 2-address opcode arithmetic, not symmetric
3504 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
3506 x := regnum(v.Args[0])
3507 y := regnum(v.Args[1])
3510 // compute -(y-x) instead
3515 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3517 opregreg(v.Op.Asm(), r, y)
3520 p := Prog(x86.ANEGQ) // TODO: use correct size? This is mostly a hack until regalloc does 2-address correctly
3521 p.To.Type = obj.TYPE_REG
3524 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3526 x := regnum(v.Args[0])
3527 y := regnum(v.Args[1])
3528 if y == r && x != r {
3529 // r/y := x op r/y, need to preserve x and rewrite to
3530 // r/y := r/y op x15
3531 x15 := int16(x86.REG_X15)
3532 // register move y to x15
3533 // register move x to y
3534 // rename y with x15
3535 opregreg(regMoveByTypeAMD64(v.Type), x15, y)
3536 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3539 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3541 opregreg(v.Op.Asm(), r, y)
3543 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
3544 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3545 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3546 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
3548 // Arg[0] is already in AX as it's the only register we allow
3549 // and AX is the only output
3550 x := regnum(v.Args[1])
3552 // CPU faults upon signed overflow, which occurs when most
3553 // negative int is divided by -1.
3555 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3556 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3557 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
3561 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
3564 // go ahead and sign extend to save doing it later
3567 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
3572 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
3577 c.From.Type = obj.TYPE_REG
3579 c.To.Type = obj.TYPE_CONST
3582 j.To.Type = obj.TYPE_BRANCH
3586 // for unsigned ints, we sign extend by setting DX = 0
3587 // signed ints were sign extended above
3588 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3589 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3590 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
3591 c := Prog(x86.AXORQ)
3592 c.From.Type = obj.TYPE_REG
3593 c.From.Reg = x86.REG_DX
3594 c.To.Type = obj.TYPE_REG
3595 c.To.Reg = x86.REG_DX
3598 p := Prog(v.Op.Asm())
3599 p.From.Type = obj.TYPE_REG
3602 // signed division, rest of the check for -1 case
3604 j2 := Prog(obj.AJMP)
3605 j2.To.Type = obj.TYPE_BRANCH
3608 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3609 v.Op == ssa.OpAMD64DIVW {
3612 n.To.Type = obj.TYPE_REG
3613 n.To.Reg = x86.REG_AX
3617 n.From.Type = obj.TYPE_REG
3618 n.From.Reg = x86.REG_DX
3619 n.To.Type = obj.TYPE_REG
3620 n.To.Reg = x86.REG_DX
3627 case ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3628 ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
3629 // the frontend rewrites constant division by 8/16/32 bit integers into
3630 // HMUL by a constant
3632 // Arg[0] is already in AX as it's the only register we allow
3633 // and DX is the only output we care about (the high bits)
3634 p := Prog(v.Op.Asm())
3635 p.From.Type = obj.TYPE_REG
3636 p.From.Reg = regnum(v.Args[1])
3638 // IMULB puts the high portion in AH instead of DL,
3639 // so move it to DL for consistency
3640 if v.Type.Size() == 1 {
3641 m := Prog(x86.AMOVB)
3642 m.From.Type = obj.TYPE_REG
3643 m.From.Reg = x86.REG_AH
3644 m.To.Type = obj.TYPE_REG
3645 m.To.Reg = x86.REG_DX
3648 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
3649 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
3650 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
3651 x := regnum(v.Args[0])
3654 if r == x86.REG_CX {
3655 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
3657 p := Prog(regMoveAMD64(v.Type.Size()))
3658 p.From.Type = obj.TYPE_REG
3660 p.To.Type = obj.TYPE_REG
3663 p := Prog(v.Op.Asm())
3664 p.From.Type = obj.TYPE_REG
3665 p.From.Reg = regnum(v.Args[1]) // should be CX
3666 p.To.Type = obj.TYPE_REG
3668 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
3669 // TODO: use addq instead of leaq if target is in the right register.
3672 case ssa.OpAMD64ADDQconst:
3674 case ssa.OpAMD64ADDLconst:
3676 case ssa.OpAMD64ADDWconst:
3680 p.From.Type = obj.TYPE_MEM
3681 p.From.Reg = regnum(v.Args[0])
3682 p.From.Offset = v.AuxInt
3683 p.To.Type = obj.TYPE_REG
3684 p.To.Reg = regnum(v)
3685 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
3687 x := regnum(v.Args[0])
3689 p := Prog(regMoveAMD64(v.Type.Size()))
3690 p.From.Type = obj.TYPE_REG
3692 p.To.Type = obj.TYPE_REG
3695 p := Prog(v.Op.Asm())
3696 p.From.Type = obj.TYPE_CONST
3697 p.From.Offset = v.AuxInt
3698 p.To.Type = obj.TYPE_REG
3700 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
3701 // instead of using the MOVQ above.
3702 //p.From3 = new(obj.Addr)
3703 //p.From3.Type = obj.TYPE_REG
3704 //p.From3.Reg = regnum(v.Args[0])
3705 case ssa.OpAMD64ADDBconst,
3706 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
3707 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
3708 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
3709 ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst, ssa.OpAMD64SUBBconst,
3710 ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst, ssa.OpAMD64SHLBconst,
3711 ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst,
3712 ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst,
3713 ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst:
3714 // This code compensates for the fact that the register allocator
3715 // doesn't understand 2-address instructions yet. TODO: fix that.
3716 x := regnum(v.Args[0])
3719 p := Prog(regMoveAMD64(v.Type.Size()))
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_CONST
3727 p.From.Offset = v.AuxInt
3728 p.To.Type = obj.TYPE_REG
3730 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
3732 p := Prog(v.Op.Asm())
3733 p.From.Type = obj.TYPE_REG
3735 p.To.Type = obj.TYPE_REG
3737 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
3738 p := Prog(x86.ALEAQ)
3739 p.From.Type = obj.TYPE_MEM
3740 p.From.Reg = regnum(v.Args[0])
3742 case ssa.OpAMD64LEAQ1:
3744 case ssa.OpAMD64LEAQ2:
3746 case ssa.OpAMD64LEAQ4:
3748 case ssa.OpAMD64LEAQ8:
3751 p.From.Index = regnum(v.Args[1])
3753 p.To.Type = obj.TYPE_REG
3754 p.To.Reg = regnum(v)
3755 case ssa.OpAMD64LEAQ:
3756 p := Prog(x86.ALEAQ)
3757 p.From.Type = obj.TYPE_MEM
3758 p.From.Reg = regnum(v.Args[0])
3760 p.To.Type = obj.TYPE_REG
3761 p.To.Reg = regnum(v)
3762 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
3763 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
3764 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
3765 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
3766 // Go assembler has swapped operands for UCOMISx relative to CMP,
3767 // must account for that right here.
3768 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
3769 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst,
3770 ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
3771 p := Prog(v.Op.Asm())
3772 p.From.Type = obj.TYPE_REG
3773 p.From.Reg = regnum(v.Args[0])
3774 p.To.Type = obj.TYPE_CONST
3775 p.To.Offset = v.AuxInt
3776 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
3778 p := Prog(v.Op.Asm())
3779 p.From.Type = obj.TYPE_CONST
3782 case ssa.OpAMD64MOVBconst:
3783 i = int64(int8(v.AuxInt))
3784 case ssa.OpAMD64MOVWconst:
3785 i = int64(int16(v.AuxInt))
3786 case ssa.OpAMD64MOVLconst:
3787 i = int64(int32(v.AuxInt))
3788 case ssa.OpAMD64MOVQconst:
3792 p.To.Type = obj.TYPE_REG
3794 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
3796 p := Prog(v.Op.Asm())
3797 p.From.Type = obj.TYPE_FCONST
3798 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
3799 p.To.Type = obj.TYPE_REG
3801 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVOload:
3802 p := Prog(v.Op.Asm())
3803 p.From.Type = obj.TYPE_MEM
3804 p.From.Reg = regnum(v.Args[0])
3806 p.To.Type = obj.TYPE_REG
3807 p.To.Reg = regnum(v)
3808 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
3809 p := Prog(v.Op.Asm())
3810 p.From.Type = obj.TYPE_MEM
3811 p.From.Reg = regnum(v.Args[0])
3814 p.From.Index = regnum(v.Args[1])
3815 p.To.Type = obj.TYPE_REG
3816 p.To.Reg = regnum(v)
3817 case ssa.OpAMD64MOVSSloadidx4:
3818 p := Prog(v.Op.Asm())
3819 p.From.Type = obj.TYPE_MEM
3820 p.From.Reg = regnum(v.Args[0])
3823 p.From.Index = regnum(v.Args[1])
3824 p.To.Type = obj.TYPE_REG
3825 p.To.Reg = regnum(v)
3826 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
3827 p := Prog(v.Op.Asm())
3828 p.From.Type = obj.TYPE_REG
3829 p.From.Reg = regnum(v.Args[1])
3830 p.To.Type = obj.TYPE_MEM
3831 p.To.Reg = regnum(v.Args[0])
3833 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
3834 p := Prog(v.Op.Asm())
3835 p.From.Type = obj.TYPE_REG
3836 p.From.Reg = regnum(v.Args[2])
3837 p.To.Type = obj.TYPE_MEM
3838 p.To.Reg = regnum(v.Args[0])
3840 p.To.Index = regnum(v.Args[1])
3842 case ssa.OpAMD64MOVSSstoreidx4:
3843 p := Prog(v.Op.Asm())
3844 p.From.Type = obj.TYPE_REG
3845 p.From.Reg = regnum(v.Args[2])
3846 p.To.Type = obj.TYPE_MEM
3847 p.To.Reg = regnum(v.Args[0])
3849 p.To.Index = regnum(v.Args[1])
3851 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
3852 p := Prog(v.Op.Asm())
3853 p.From.Type = obj.TYPE_CONST
3854 sc := ssa.StoreConst(v.AuxInt)
3857 case ssa.OpAMD64MOVBstoreconst:
3859 case ssa.OpAMD64MOVWstoreconst:
3861 case ssa.OpAMD64MOVLstoreconst:
3863 case ssa.OpAMD64MOVQstoreconst:
3866 p.To.Type = obj.TYPE_MEM
3867 p.To.Reg = regnum(v.Args[0])
3868 addAux2(&p.To, v, sc.Off())
3869 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
3870 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
3871 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
3872 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
3873 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
3874 case ssa.OpAMD64DUFFZERO:
3875 p := Prog(obj.ADUFFZERO)
3876 p.To.Type = obj.TYPE_ADDR
3877 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
3878 p.To.Offset = v.AuxInt
3879 case ssa.OpAMD64MOVOconst:
3881 v.Unimplementedf("MOVOconst can only do constant=0")
3884 opregreg(x86.AXORPS, r, r)
3885 case ssa.OpAMD64DUFFCOPY:
3886 p := Prog(obj.ADUFFCOPY)
3887 p.To.Type = obj.TYPE_ADDR
3888 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
3889 p.To.Offset = v.AuxInt
3891 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: lower Copy to MOVQ earlier?
3892 if v.Type.IsMemory() {
3895 x := regnum(v.Args[0])
3898 opregreg(regMoveByTypeAMD64(v.Type), y, x)
3901 if v.Type.IsFlags() {
3902 v.Unimplementedf("load flags not implemented: %v", v.LongString())
3905 p := Prog(movSizeByType(v.Type))
3906 n, off := autoVar(v.Args[0])
3907 p.From.Type = obj.TYPE_MEM
3909 p.From.Sym = Linksym(n.Sym)
3911 if n.Class == PPARAM {
3912 p.From.Name = obj.NAME_PARAM
3913 p.From.Offset += n.Xoffset
3915 p.From.Name = obj.NAME_AUTO
3917 p.To.Type = obj.TYPE_REG
3918 p.To.Reg = regnum(v)
3920 case ssa.OpStoreReg:
3921 if v.Type.IsFlags() {
3922 v.Unimplementedf("store flags not implemented: %v", v.LongString())
3925 p := Prog(movSizeByType(v.Type))
3926 p.From.Type = obj.TYPE_REG
3927 p.From.Reg = regnum(v.Args[0])
3928 n, off := autoVar(v)
3929 p.To.Type = obj.TYPE_MEM
3931 p.To.Sym = Linksym(n.Sym)
3933 if n.Class == PPARAM {
3934 p.To.Name = obj.NAME_PARAM
3935 p.To.Offset += n.Xoffset
3937 p.To.Name = obj.NAME_AUTO
3940 // just check to make sure regalloc and stackalloc did it right
3941 if v.Type.IsMemory() {
3945 loc := f.RegAlloc[v.ID]
3946 for _, a := range v.Args {
3947 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
3948 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)
3951 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64, ssa.OpConstString, ssa.OpConstNil, ssa.OpConstBool,
3952 ssa.OpConst32F, ssa.OpConst64F:
3953 if v.Block.Func.RegAlloc[v.ID] != nil {
3954 v.Fatalf("const value %v shouldn't have a location", v)
3958 // memory arg needs no code
3960 // input args need no code
3961 case ssa.OpAMD64LoweredGetClosurePtr:
3962 // Output is hardwired to DX only,
3963 // and DX contains the closure pointer on
3964 // closure entry, and this "instruction"
3965 // is scheduled to the very beginning
3966 // of the entry block.
3967 case ssa.OpAMD64LoweredGetG:
3969 // See the comments in cmd/internal/obj/x86/obj6.go
3970 // near CanUse1InsnTLS for a detailed explanation of these instructions.
3971 if x86.CanUse1InsnTLS(Ctxt) {
3973 p := Prog(x86.AMOVQ)
3974 p.From.Type = obj.TYPE_MEM
3975 p.From.Reg = x86.REG_TLS
3976 p.To.Type = obj.TYPE_REG
3980 // MOVQ (r)(TLS*1), r
3981 p := Prog(x86.AMOVQ)
3982 p.From.Type = obj.TYPE_REG
3983 p.From.Reg = x86.REG_TLS
3984 p.To.Type = obj.TYPE_REG
3986 q := Prog(x86.AMOVQ)
3987 q.From.Type = obj.TYPE_MEM
3989 q.From.Index = x86.REG_TLS
3991 q.To.Type = obj.TYPE_REG
3994 case ssa.OpAMD64CALLstatic:
3995 p := Prog(obj.ACALL)
3996 p.To.Type = obj.TYPE_MEM
3997 p.To.Name = obj.NAME_EXTERN
3998 p.To.Sym = Linksym(v.Aux.(*Sym))
3999 if Maxarg < v.AuxInt {
4002 case ssa.OpAMD64CALLclosure:
4003 p := Prog(obj.ACALL)
4004 p.To.Type = obj.TYPE_REG
4005 p.To.Reg = regnum(v.Args[0])
4006 if Maxarg < v.AuxInt {
4009 case ssa.OpAMD64CALLdefer:
4010 p := Prog(obj.ACALL)
4011 p.To.Type = obj.TYPE_MEM
4012 p.To.Name = obj.NAME_EXTERN
4013 p.To.Sym = Linksym(Deferproc.Sym)
4014 if Maxarg < v.AuxInt {
4017 // defer returns in rax:
4018 // 0 if we should continue executing
4019 // 1 if we should jump to deferreturn call
4020 p = Prog(x86.ATESTL)
4021 p.From.Type = obj.TYPE_REG
4022 p.From.Reg = x86.REG_AX
4023 p.To.Type = obj.TYPE_REG
4024 p.To.Reg = x86.REG_AX
4026 p.To.Type = obj.TYPE_BRANCH
4027 s.deferBranches = append(s.deferBranches, p)
4028 case ssa.OpAMD64CALLgo:
4029 p := Prog(obj.ACALL)
4030 p.To.Type = obj.TYPE_MEM
4031 p.To.Name = obj.NAME_EXTERN
4032 p.To.Sym = Linksym(Newproc.Sym)
4033 if Maxarg < v.AuxInt {
4036 case ssa.OpAMD64CALLinter:
4037 p := Prog(obj.ACALL)
4038 p.To.Type = obj.TYPE_REG
4039 p.To.Reg = regnum(v.Args[0])
4040 if Maxarg < v.AuxInt {
4043 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4044 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
4045 x := regnum(v.Args[0])
4048 p := Prog(regMoveAMD64(v.Type.Size()))
4049 p.From.Type = obj.TYPE_REG
4051 p.To.Type = obj.TYPE_REG
4054 p := Prog(v.Op.Asm())
4055 p.To.Type = obj.TYPE_REG
4057 case ssa.OpAMD64SQRTSD:
4058 p := Prog(v.Op.Asm())
4059 p.From.Type = obj.TYPE_REG
4060 p.From.Reg = regnum(v.Args[0])
4061 p.To.Type = obj.TYPE_REG
4062 p.To.Reg = regnum(v)
4063 case ssa.OpSP, ssa.OpSB:
4065 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4066 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4067 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
4068 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
4069 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
4070 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
4071 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
4072 p := Prog(v.Op.Asm())
4073 p.To.Type = obj.TYPE_REG
4074 p.To.Reg = regnum(v)
4076 case ssa.OpAMD64SETNEF:
4077 p := Prog(v.Op.Asm())
4078 p.To.Type = obj.TYPE_REG
4079 p.To.Reg = regnum(v)
4080 q := Prog(x86.ASETPS)
4081 q.To.Type = obj.TYPE_REG
4082 q.To.Reg = x86.REG_AX
4083 // TODO AORQ copied from old code generator, why not AORB?
4084 opregreg(x86.AORQ, regnum(v), x86.REG_AX)
4086 case ssa.OpAMD64SETEQF:
4087 p := Prog(v.Op.Asm())
4088 p.To.Type = obj.TYPE_REG
4089 p.To.Reg = regnum(v)
4090 q := Prog(x86.ASETPC)
4091 q.To.Type = obj.TYPE_REG
4092 q.To.Reg = x86.REG_AX
4093 // TODO AANDQ copied from old code generator, why not AANDB?
4094 opregreg(x86.AANDQ, regnum(v), x86.REG_AX)
4096 case ssa.OpAMD64InvertFlags:
4097 v.Fatalf("InvertFlags should never make it to codegen %v", v)
4098 case ssa.OpAMD64REPSTOSQ:
4101 case ssa.OpAMD64REPMOVSQ:
4105 Gvardef(v.Aux.(*Node))
4107 gvarkill(v.Aux.(*Node))
4108 case ssa.OpAMD64LoweredNilCheck:
4109 // Optimization - if the subsequent block has a load or store
4110 // at the same address, we don't need to issue this instruction.
4111 for _, w := range v.Block.Succs[0].Values {
4112 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4113 // w doesn't use a store - can't be a memory op.
4116 if w.Args[len(w.Args)-1] != v.Args[1] {
4117 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4120 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
4121 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore:
4122 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
4125 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4126 off := ssa.StoreConst(v.AuxInt).Off()
4127 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
4131 if w.Type.IsMemory() {
4132 // We can't delay the nil check past the next store.
4136 // Issue a load which will fault if the input is nil.
4137 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4138 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4139 // but it doesn't have false dependency on AX.
4140 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4141 // That trades clobbering flags for clobbering a register.
4142 p := Prog(x86.ATESTB)
4143 p.From.Type = obj.TYPE_REG
4144 p.From.Reg = x86.REG_AX
4145 p.To.Type = obj.TYPE_MEM
4146 p.To.Reg = regnum(v.Args[0])
4148 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
4149 Warnl(int(v.Line), "generated nil check")
4152 v.Unimplementedf("genValue not implemented: %s", v.LongString())
4156 // movSizeByType returns the MOV instruction of the given type.
4157 func movSizeByType(t ssa.Type) (asm int) {
4158 // For x86, there's no difference between reg move opcodes
4159 // and memory move opcodes.
4160 asm = regMoveByTypeAMD64(t)
4164 // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4165 func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4167 // TODO: use zero register on archs that support it.
4168 p.From.Type = obj.TYPE_CONST
4170 p.To.Type = obj.TYPE_MEM
4172 p.To.Offset = offset
4174 nleft = nbytes - width
4175 return nleft, offset
4178 var blockJump = [...]struct {
4181 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4182 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4183 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4184 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4185 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4186 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4187 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4188 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4189 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4190 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
4191 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4192 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4195 type floatingEQNEJump struct {
4199 var eqfJumps = [2][2]floatingEQNEJump{
4200 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4201 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4203 var nefJumps = [2][2]floatingEQNEJump{
4204 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4205 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4208 func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4209 p := Prog(jumps.jump)
4210 p.To.Type = obj.TYPE_BRANCH
4212 branches = append(branches, branch{p, b.Succs[to]})
4216 // liblink reorders the instruction stream as it sees fit.
4217 // Pass along what we know so liblink can make use of it.
4218 // TODO: Once we've fully switched to SSA,
4219 // make liblink leave our output alone.
4221 case ssa.BranchUnlikely:
4222 p.From.Type = obj.TYPE_CONST
4224 case ssa.BranchLikely:
4225 p.From.Type = obj.TYPE_CONST
4231 func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
4235 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4236 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
4238 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4239 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4241 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4242 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4244 q.To.Type = obj.TYPE_BRANCH
4245 s.branches = append(s.branches, branch{q, b.Succs[1]})
4249 func (s *genState) genBlock(b, next *ssa.Block) {
4253 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
4254 if b.Succs[0] != next {
4256 p.To.Type = obj.TYPE_BRANCH
4257 s.branches = append(s.branches, branch{p, b.Succs[0]})
4260 Prog(obj.AUNDEF) // tell plive.go that we never reach here
4266 case ssa.BlockRetJmp:
4268 p.To.Type = obj.TYPE_MEM
4269 p.To.Name = obj.NAME_EXTERN
4270 p.To.Sym = Linksym(b.Aux.(*Sym))
4272 case ssa.BlockAMD64EQF:
4273 genFPJump(s, b, next, &eqfJumps)
4275 case ssa.BlockAMD64NEF:
4276 genFPJump(s, b, next, &nefJumps)
4278 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4279 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4280 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4281 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4282 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
4283 jmp := blockJump[b.Kind]
4288 p = Prog(jmp.invasm)
4290 p.To.Type = obj.TYPE_BRANCH
4291 s.branches = append(s.branches, branch{p, b.Succs[1]})
4294 p.To.Type = obj.TYPE_BRANCH
4295 s.branches = append(s.branches, branch{p, b.Succs[0]})
4298 p.To.Type = obj.TYPE_BRANCH
4299 s.branches = append(s.branches, branch{p, b.Succs[0]})
4301 q.To.Type = obj.TYPE_BRANCH
4302 s.branches = append(s.branches, branch{q, b.Succs[1]})
4305 // liblink reorders the instruction stream as it sees fit.
4306 // Pass along what we know so liblink can make use of it.
4307 // TODO: Once we've fully switched to SSA,
4308 // make liblink leave our output alone.
4310 case ssa.BranchUnlikely:
4311 p.From.Type = obj.TYPE_CONST
4313 case ssa.BranchLikely:
4314 p.From.Type = obj.TYPE_CONST
4319 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
4323 func (s *genState) deferReturn() {
4324 // Deferred calls will appear to be returning to
4325 // the CALL deferreturn(SB) that we are about to emit.
4326 // However, the stack trace code will show the line
4327 // of the instruction byte before the return PC.
4328 // To avoid that being an unrelated instruction,
4329 // insert an actual hardware NOP that will have the right line number.
4330 // This is different from obj.ANOP, which is a virtual no-op
4331 // that doesn't make it into the instruction stream.
4334 p := Prog(obj.ACALL)
4335 p.To.Type = obj.TYPE_MEM
4336 p.To.Name = obj.NAME_EXTERN
4337 p.To.Sym = Linksym(Deferreturn.Sym)
4340 // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4341 func addAux(a *obj.Addr, v *ssa.Value) {
4342 addAux2(a, v, v.AuxInt)
4344 func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
4345 if a.Type != obj.TYPE_MEM {
4346 v.Fatalf("bad addAux addr %s", a)
4348 // add integer offset
4351 // If no additional symbol offset, we're done.
4355 // Add symbol's offset from its base register.
4356 switch sym := v.Aux.(type) {
4357 case *ssa.ExternSymbol:
4358 a.Name = obj.NAME_EXTERN
4359 a.Sym = Linksym(sym.Sym.(*Sym))
4360 case *ssa.ArgSymbol:
4361 n := sym.Node.(*Node)
4362 a.Name = obj.NAME_PARAM
4364 a.Sym = Linksym(n.Orig.Sym)
4365 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
4366 case *ssa.AutoSymbol:
4367 n := sym.Node.(*Node)
4368 a.Name = obj.NAME_AUTO
4370 a.Sym = Linksym(n.Sym)
4372 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4376 // extendIndex extends v to a full int width.
4377 func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4378 size := v.Type.Size()
4379 if size == s.config.IntSize {
4382 if size > s.config.IntSize {
4383 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
4384 // the high word and branch to out-of-bounds failure if it is not 0.
4385 s.Unimplementedf("64->32 index truncation not implemented")
4389 // Extend value to the required size
4391 if v.Type.IsSigned() {
4392 switch 10*size + s.config.IntSize {
4394 op = ssa.OpSignExt8to32
4396 op = ssa.OpSignExt8to64
4398 op = ssa.OpSignExt16to32
4400 op = ssa.OpSignExt16to64
4402 op = ssa.OpSignExt32to64
4404 s.Fatalf("bad signed index extension %s", v.Type)
4407 switch 10*size + s.config.IntSize {
4409 op = ssa.OpZeroExt8to32
4411 op = ssa.OpZeroExt8to64
4413 op = ssa.OpZeroExt16to32
4415 op = ssa.OpZeroExt16to64
4417 op = ssa.OpZeroExt32to64
4419 s.Fatalf("bad unsigned index extension %s", v.Type)
4422 return s.newValue1(op, Types[TINT], v)
4425 // ssaRegToReg maps ssa register numbers to obj register numbers.
4426 var ssaRegToReg = [...]int16{
4459 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
4460 // TODO: arch-dependent
4463 // regMoveAMD64 returns the register->register move opcode for the given width.
4464 // TODO: generalize for all architectures?
4465 func regMoveAMD64(width int64) int {
4476 panic("bad int register width")
4480 func regMoveByTypeAMD64(t ssa.Type) int {
4489 panic("bad float register width")
4502 panic("bad int register width")
4506 panic("bad register type")
4509 // regnum returns the register (in cmd/internal/obj numbering) to
4510 // which v has been allocated. Panics if v is not assigned to a
4512 // TODO: Make this panic again once it stops happening routinely.
4513 func regnum(v *ssa.Value) int16 {
4514 reg := v.Block.Func.RegAlloc[v.ID]
4516 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
4519 return ssaRegToReg[reg.(*ssa.Register).Num]
4522 // autoVar returns a *Node and int64 representing the auto variable and offset within it
4523 // where v should be spilled.
4524 func autoVar(v *ssa.Value) (*Node, int64) {
4525 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
4526 return loc.N.(*Node), loc.Off
4529 // ssaExport exports a bunch of compiler services for the ssa backend.
4530 type ssaExport struct {
4536 func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
4537 func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
4538 func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
4539 func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
4540 func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
4541 func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
4542 func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
4543 func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
4544 func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
4545 func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
4546 func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
4547 func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
4548 func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
4549 func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
4550 func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
4552 // StringData returns a symbol (a *Sym wrapped in an interface) which
4553 // is the data component of a global string constant containing s.
4554 func (*ssaExport) StringData(s string) interface{} {
4555 // TODO: is idealstring correct? It might not matter...
4556 _, data := stringsym(s)
4557 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
4560 func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
4561 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
4562 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
4566 func (e *ssaExport) CanSSA(t ssa.Type) bool {
4567 return canSSAType(t.(*Type))
4570 // Log logs a message from the compiler.
4571 func (e *ssaExport) Logf(msg string, args ...interface{}) {
4572 // If e was marked as unimplemented, anything could happen. Ignore.
4573 if e.log && !e.unimplemented {
4574 fmt.Printf(msg, args...)
4578 // Fatal reports a compiler error and exits.
4579 func (e *ssaExport) Fatalf(msg string, args ...interface{}) {
4580 // If e was marked as unimplemented, anything could happen. Ignore.
4581 if !e.unimplemented {
4582 Fatalf(msg, args...)
4586 // Unimplemented reports that the function cannot be compiled.
4587 // It will be removed once SSA work is complete.
4588 func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) {
4589 if e.mustImplement {
4590 Fatalf(msg, args...)
4592 const alwaysLog = false // enable to calculate top unimplemented features
4593 if !e.unimplemented && (e.log || alwaysLog) {
4594 // first implementation failure, print explanation
4595 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4597 e.unimplemented = true
4600 // Warnl reports a "warning", which is usually flag-triggered
4601 // logging output for the benefit of tests.
4602 func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
4603 Warnl(line, fmt_, args...)
4606 func (e *ssaExport) Debug_checknil() bool {
4607 return Debug_checknil != 0
4610 func (n *Node) Typ() ssa.Type {