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 var ssaConfig *ssa.Config
27 func shouldssa(fn *Node) bool {
28 if Thearch.Thestring != "amd64" {
32 // Environment variable control of SSA CG
33 // 1. IF GOSSAFUNC == current function name THEN
34 // compile this function with SSA and log output to ssa.html
36 // 2. IF GOSSAHASH == "" THEN
37 // compile this function (and everything else) with SSA
39 // 3. IF GOSSAHASH == "n" or "N"
40 // IF GOSSAPKG == current package name THEN
41 // compile this function (and everything in this package) with SSA
43 // use the old back end for this function.
44 // This is for compatibility with existing test harness and should go away.
46 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
47 // compile this function with SSA
49 // compile this function with the old back end.
51 // Plan is for 3 to be removed when the tests are revised.
52 // SSA is now default, and is disabled by setting
53 // GOSSAHASH to n or N, or selectively with strings of
56 name := fn.Func.Nname.Sym.Name
58 funcname := os.Getenv("GOSSAFUNC")
60 // If GOSSAFUNC is set, compile only that function.
61 return name == funcname
64 pkg := os.Getenv("GOSSAPKG")
66 // If GOSSAPKG is set, compile only that package.
67 return localpkg.Name == pkg
70 gossahash := os.Getenv("GOSSAHASH")
71 if gossahash == "" || gossahash == "y" || gossahash == "Y" {
74 if gossahash == "n" || gossahash == "N" {
78 // Check the hash of the name against a partial input hash.
79 // We use this feature to do a binary search within a package to
80 // find a function that is incorrectly compiled.
82 for _, b := range sha1.Sum([]byte(name)) {
83 hstr += fmt.Sprintf("%08b", b)
86 if strings.HasSuffix(hstr, gossahash) {
87 fmt.Printf("GOSSAHASH triggered %s\n", name)
91 // Iteratively try additional hashes to allow tests for multi-point
93 for i := 0; true; i++ {
94 ev := fmt.Sprintf("GOSSAHASH%d", i)
99 if strings.HasSuffix(hstr, evv) {
100 fmt.Printf("%s triggered %s\n", ev, name)
108 // buildssa builds an SSA function.
109 func buildssa(fn *Node) *ssa.Func {
110 name := fn.Func.Nname.Sym.Name
111 printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
113 fmt.Println("generating SSA for", name)
114 dumplist("buildssa-enter", fn.Func.Enter)
115 dumplist("buildssa-body", fn.Nbody)
116 dumplist("buildssa-exit", fn.Func.Exit)
120 s.pushLine(fn.Lineno)
123 // TODO(khr): build config just once at the start of the compiler binary
125 ssaExp.log = printssa
126 ssaExp.unimplemented = false
127 ssaExp.mustImplement = true
128 if ssaConfig == nil {
129 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
132 s.f = s.config.NewFunc()
134 s.exitCode = fn.Func.Exit
135 s.panics = map[funcLine]*ssa.Block{}
137 if name == os.Getenv("GOSSAFUNC") {
138 // TODO: tempfile? it is handy to have the location
139 // of this file be stable, so you can just reload in the browser.
140 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
141 // TODO: generate and print a mapping from nodes to values and blocks
145 s.config.HTML.Close()
149 // Allocate starting block
150 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
152 // Allocate starting values
153 s.labels = map[string]*ssaLabel{}
154 s.labeledNodes = map[*Node]*ssaLabel{}
155 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
156 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
157 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
159 s.startBlock(s.f.Entry)
160 s.vars[&memVar] = s.startmem
162 s.varsyms = map[*Node]interface{}{}
164 // Generate addresses of local declarations
165 s.decladdrs = map[*Node]*ssa.Value{}
166 for d := fn.Func.Dcl; d != nil; d = d.Next {
170 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
171 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
173 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
174 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
175 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
176 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
177 // This ends up wrong, have to do it at the PARAM node instead.
178 case PAUTO, PPARAMOUT:
179 // processed at each use, to prevent Addr coming
182 // local function - already handled by frontend
185 if n.Class&PHEAP != 0 {
188 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
192 // Convert the AST-based IR to the SSA-based IR
193 s.stmtList(fn.Func.Enter)
196 // fallthrough to exit
197 if s.curBlock != nil {
198 s.stmtList(s.exitCode)
201 b.Kind = ssa.BlockRet
205 // Check that we used all labels
206 for name, lab := range s.labels {
207 if !lab.used() && !lab.reported {
208 yyerrorl(int(lab.defNode.Lineno), "label %v defined and not used", name)
211 if lab.used() && !lab.defined() && !lab.reported {
212 yyerrorl(int(lab.useNode.Lineno), "label %v not defined", name)
217 // Check any forward gotos. Non-forward gotos have already been checked.
218 for _, n := range s.fwdGotos {
219 lab := s.labels[n.Left.Sym.Name]
220 // If the label is undefined, we have already have printed an error.
222 s.checkgoto(n, lab.defNode)
231 // Link up variable uses to variable definitions
232 s.linkForwardReferences()
234 // Don't carry reference this around longer than necessary
237 // Main call to ssa package to compile function
244 // configuration (arch) information
247 // function we're building
250 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
251 labels map[string]*ssaLabel
252 labeledNodes map[*Node]*ssaLabel
254 // gotos that jump forward; required for deferred checkgoto calls
256 // Code that must precede any return
257 // (e.g., copying value of heap-escaped paramout back to true paramout)
260 // unlabeled break and continue statement tracking
261 breakTo *ssa.Block // current target for plain break statement
262 continueTo *ssa.Block // current target for plain continue statement
264 // current location where we're interpreting the AST
267 // variable assignments in the current block (map from variable symbol to ssa value)
268 // *Node is the unique identifier (an ONAME Node) for the variable.
269 vars map[*Node]*ssa.Value
271 // all defined variables at the end of each block. Indexed by block ID.
272 defvars []map[*Node]*ssa.Value
274 // addresses of PPARAM and PPARAMOUT variables.
275 decladdrs map[*Node]*ssa.Value
277 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
278 varsyms map[*Node]interface{}
280 // starting values. Memory, stack pointer, and globals pointer
285 // line number stack. The current line number is top of stack
288 // list of panic calls by function name and line number.
289 // Used to deduplicate panic calls.
290 panics map[funcLine]*ssa.Block
292 // list of FwdRef values.
296 type funcLine struct {
301 type ssaLabel struct {
302 target *ssa.Block // block identified by this label
303 breakTarget *ssa.Block // block to break to in control flow node identified by this label
304 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
305 defNode *Node // label definition Node (OLABEL)
306 // Label use Node (OGOTO, OBREAK, OCONTINUE).
307 // Used only for error detection and reporting.
308 // There might be multiple uses, but we only need to track one.
310 reported bool // reported indicates whether an error has already been reported for this label
313 // defined reports whether the label has a definition (OLABEL node).
314 func (l *ssaLabel) defined() bool { return l.defNode != nil }
316 // used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
317 func (l *ssaLabel) used() bool { return l.useNode != nil }
319 // label returns the label associated with sym, creating it if necessary.
320 func (s *state) label(sym *Sym) *ssaLabel {
321 lab := s.labels[sym.Name]
324 s.labels[sym.Name] = lab
329 func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
330 func (s *state) Log() bool { return s.config.Log() }
331 func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
332 func (s *state) Unimplementedf(msg string, args ...interface{}) {
333 s.config.Unimplementedf(s.peekLine(), msg, args...)
335 func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
336 func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
339 // dummy node for the memory variable
340 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
342 // dummy nodes for temporary variables
343 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
344 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
345 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
346 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
347 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
350 // startBlock sets the current block we're generating code in to b.
351 func (s *state) startBlock(b *ssa.Block) {
352 if s.curBlock != nil {
353 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
356 s.vars = map[*Node]*ssa.Value{}
359 // endBlock marks the end of generating code for the current block.
360 // Returns the (former) current block. Returns nil if there is no current
361 // block, i.e. if no code flows to the current execution point.
362 func (s *state) endBlock() *ssa.Block {
367 for len(s.defvars) <= int(b.ID) {
368 s.defvars = append(s.defvars, nil)
370 s.defvars[b.ID] = s.vars
373 b.Line = s.peekLine()
377 // pushLine pushes a line number on the line number stack.
378 func (s *state) pushLine(line int32) {
379 s.line = append(s.line, line)
382 // popLine pops the top of the line number stack.
383 func (s *state) popLine() {
384 s.line = s.line[:len(s.line)-1]
387 // peekLine peek the top of the line number stack.
388 func (s *state) peekLine() int32 {
389 return s.line[len(s.line)-1]
392 func (s *state) Error(msg string, args ...interface{}) {
393 yyerrorl(int(s.peekLine()), msg, args...)
396 // newValue0 adds a new value with no arguments to the current block.
397 func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
398 return s.curBlock.NewValue0(s.peekLine(), op, t)
401 // newValue0A adds a new value with no arguments and an aux value to the current block.
402 func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
403 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
406 // newValue0I adds a new value with no arguments and an auxint value to the current block.
407 func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
408 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
411 // newValue1 adds a new value with one argument to the current block.
412 func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
413 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
416 // newValue1A adds a new value with one argument and an aux value to the current block.
417 func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
418 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
421 // newValue1I adds a new value with one argument and an auxint value to the current block.
422 func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
423 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
426 // newValue2 adds a new value with two arguments to the current block.
427 func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
428 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
431 // newValue2I adds a new value with two arguments and an auxint value to the current block.
432 func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
433 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
436 // newValue3 adds a new value with three arguments to the current block.
437 func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
438 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
441 // newValue3I adds a new value with three arguments and an auxint value to the current block.
442 func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
443 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
446 // entryNewValue0 adds a new value with no arguments to the entry block.
447 func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
448 return s.f.Entry.NewValue0(s.peekLine(), op, t)
451 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
452 func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
453 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
456 // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
457 func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
458 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
461 // entryNewValue1 adds a new value with one argument to the entry block.
462 func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
463 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
466 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
467 func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
468 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
471 // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
472 func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
473 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
476 // entryNewValue2 adds a new value with two arguments to the entry block.
477 func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
478 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
481 // const* routines add a new const value to the entry block.
482 func (s *state) constBool(c bool) *ssa.Value {
483 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
485 func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
486 return s.f.ConstInt8(s.peekLine(), t, c)
488 func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
489 return s.f.ConstInt16(s.peekLine(), t, c)
491 func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
492 return s.f.ConstInt32(s.peekLine(), t, c)
494 func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
495 return s.f.ConstInt64(s.peekLine(), t, c)
497 func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
498 return s.f.ConstFloat32(s.peekLine(), t, c)
500 func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
501 return s.f.ConstFloat64(s.peekLine(), t, c)
503 func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
504 if s.config.IntSize == 8 {
505 return s.constInt64(t, c)
507 if int64(int32(c)) != c {
508 s.Fatalf("integer constant too big %d", c)
510 return s.constInt32(t, int32(c))
513 // ssaStmtList converts the statement n to SSA and adds it to s.
514 func (s *state) stmtList(l *NodeList) {
515 for ; l != nil; l = l.Next {
520 // ssaStmt converts the statement n to SSA and adds it to s.
521 func (s *state) stmt(n *Node) {
525 // If s.curBlock is nil, then we're about to generate dead code.
526 // We can't just short-circuit here, though,
527 // because we check labels and gotos as part of SSA generation.
528 // Provide a block for the dead code so that we don't have
529 // to add special cases everywhere else.
530 if s.curBlock == nil {
531 dead := s.f.NewBlock(ssa.BlockPlain)
542 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
544 // Expression statements
545 case OCALLFUNC, OCALLMETH, OCALLINTER:
546 s.call(n, callNormal)
547 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC && n.Left.Sym.Pkg == Runtimepkg &&
548 (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo") {
551 b.Kind = ssa.BlockExit
553 // TODO: never rewrite OPANIC to OCALLFUNC in the
554 // first place. Need to wait until all backends
558 s.call(n.Left, callDefer)
560 s.call(n.Left, callGo)
563 res, resok := s.dottype(n.Rlist.N, true)
564 s.assign(n.List.N, res, false, false, n.Lineno)
565 s.assign(n.List.Next.N, resok, false, false, n.Lineno)
569 if n.Left.Class&PHEAP == 0 {
572 if compiling_runtime != 0 {
573 Fatalf("%v escapes to heap, not allowed in runtime.", n)
576 // TODO: the old pass hides the details of PHEAP
577 // variables behind ONAME nodes. Figure out if it's better
578 // to rewrite the tree and make the heapaddr construct explicit
579 // or to keep this detail hidden behind the scenes.
580 palloc := prealloc[n.Left]
582 palloc = callnew(n.Left.Type)
583 prealloc[n.Left] = palloc
586 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno)
592 // Empty identifier is valid but useless.
593 // See issues 11589, 11593.
599 // Associate label with its control flow node, if any
600 if ctl := n.Name.Defn; ctl != nil {
602 case OFOR, OSWITCH, OSELECT:
603 s.labeledNodes[ctl] = lab
610 s.Error("label %v already defined at %v", sym, Ctxt.Line(int(lab.defNode.Lineno)))
613 // The label might already have a target block via a goto.
614 if lab.target == nil {
615 lab.target = s.f.NewBlock(ssa.BlockPlain)
618 // go to that label (we pretend "label:" is preceded by "goto label")
620 b.AddEdgeTo(lab.target)
621 s.startBlock(lab.target)
627 if lab.target == nil {
628 lab.target = s.f.NewBlock(ssa.BlockPlain)
635 s.checkgoto(n, lab.defNode)
637 s.fwdGotos = append(s.fwdGotos, n)
641 b.AddEdgeTo(lab.target)
644 // Check whether we can generate static data rather than code.
645 // If so, ignore n and defer data generation until codegen.
646 // Failure to do this causes writes to readonly symbols.
647 if gen_as_init(n, true) {
649 if s.f.StaticData != nil {
650 data = s.f.StaticData.([]*Node)
652 s.f.StaticData = append(data, n)
665 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
666 // All literals with nonzero fields have already been
667 // rewritten during walk. Any that remain are just T{}
668 // or equivalents. Use the zero value.
670 Fatalf("literal with nonzero value in SSA: %v", rhs)
675 needwb := n.Op == OASWB && rhs != nil
676 deref := !canSSAType(t)
679 r = nil // Signal assign to use OpZero.
681 r = s.addr(rhs, false)
690 if rhs != nil && rhs.Op == OAPPEND {
691 // Yuck! The frontend gets rid of the write barrier, but we need it!
692 // At least, we need it in the case where growslice is called.
693 // TODO: Do the write barrier on just the growslice branch.
694 // TODO: just add a ptr graying to the end of growslice?
695 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
696 // They get similar wb-removal treatment in walk.go:OAS.
700 s.assign(n.Left, r, needwb, deref, n.Lineno)
703 bThen := s.f.NewBlock(ssa.BlockPlain)
704 bEnd := s.f.NewBlock(ssa.BlockPlain)
707 bElse = s.f.NewBlock(ssa.BlockPlain)
708 s.condBranch(n.Left, bThen, bElse, n.Likely)
710 s.condBranch(n.Left, bThen, bEnd, n.Likely)
715 if b := s.endBlock(); b != nil {
722 if b := s.endBlock(); b != nil {
730 s.stmtList(s.exitCode)
733 b.Kind = ssa.BlockRet
737 s.stmtList(s.exitCode)
740 b.Kind = ssa.BlockRetJmp
744 case OCONTINUE, OBREAK:
756 // plain break/continue
758 s.Error("%s is not in a loop", op)
761 // nothing to do; "to" is already the correct target
763 // labeled break/continue; look up the target
770 s.Error("%s label not defined: %v", op, sym)
776 to = lab.continueTarget
781 // Valid label but not usable with a break/continue here, e.g.:
787 s.Error("invalid %s label %v", op, sym)
797 // OFOR: for Ninit; Left; Right { Nbody }
798 bCond := s.f.NewBlock(ssa.BlockPlain)
799 bBody := s.f.NewBlock(ssa.BlockPlain)
800 bIncr := s.f.NewBlock(ssa.BlockPlain)
801 bEnd := s.f.NewBlock(ssa.BlockPlain)
803 // first, jump to condition test
807 // generate code to test condition
810 s.condBranch(n.Left, bBody, bEnd, 1)
813 b.Kind = ssa.BlockPlain
817 // set up for continue/break in body
818 prevContinue := s.continueTo
819 prevBreak := s.breakTo
822 lab := s.labeledNodes[n]
825 lab.continueTarget = bIncr
826 lab.breakTarget = bEnd
833 // tear down continue/break
834 s.continueTo = prevContinue
835 s.breakTo = prevBreak
837 lab.continueTarget = nil
838 lab.breakTarget = nil
841 // done with body, goto incr
842 if b := s.endBlock(); b != nil {
851 if b := s.endBlock(); b != nil {
856 case OSWITCH, OSELECT:
857 // These have been mostly rewritten by the front end into their Nbody fields.
858 // Our main task is to correctly hook up any break statements.
859 bEnd := s.f.NewBlock(ssa.BlockPlain)
861 prevBreak := s.breakTo
863 lab := s.labeledNodes[n]
866 lab.breakTarget = bEnd
869 // generate body code
872 s.breakTo = prevBreak
874 lab.breakTarget = nil
877 // OSWITCH never falls through (s.curBlock == nil here).
878 // OSELECT does not fall through if we're calling selectgo.
879 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
880 // In those latter cases, go to the code after the select.
881 if b := s.endBlock(); b != nil {
887 // Insert a varkill op to record that a variable is no longer live.
888 // We only care about liveness info at call sites, so putting the
889 // varkill in the store chain is enough to keep it correctly ordered
890 // with respect to call ops.
892 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
896 // Insert a varlive op to record that a variable is still live.
897 if !n.Left.Addrtaken {
898 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
900 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
907 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
911 type opAndType struct {
916 var opToSSA = map[opAndType]ssa.Op{
917 opAndType{OADD, TINT8}: ssa.OpAdd8,
918 opAndType{OADD, TUINT8}: ssa.OpAdd8,
919 opAndType{OADD, TINT16}: ssa.OpAdd16,
920 opAndType{OADD, TUINT16}: ssa.OpAdd16,
921 opAndType{OADD, TINT32}: ssa.OpAdd32,
922 opAndType{OADD, TUINT32}: ssa.OpAdd32,
923 opAndType{OADD, TPTR32}: ssa.OpAdd32,
924 opAndType{OADD, TINT64}: ssa.OpAdd64,
925 opAndType{OADD, TUINT64}: ssa.OpAdd64,
926 opAndType{OADD, TPTR64}: ssa.OpAdd64,
927 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
928 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
930 opAndType{OSUB, TINT8}: ssa.OpSub8,
931 opAndType{OSUB, TUINT8}: ssa.OpSub8,
932 opAndType{OSUB, TINT16}: ssa.OpSub16,
933 opAndType{OSUB, TUINT16}: ssa.OpSub16,
934 opAndType{OSUB, TINT32}: ssa.OpSub32,
935 opAndType{OSUB, TUINT32}: ssa.OpSub32,
936 opAndType{OSUB, TINT64}: ssa.OpSub64,
937 opAndType{OSUB, TUINT64}: ssa.OpSub64,
938 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
939 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
941 opAndType{ONOT, TBOOL}: ssa.OpNot,
943 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
944 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
945 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
946 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
947 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
948 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
949 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
950 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
951 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
952 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
954 opAndType{OCOM, TINT8}: ssa.OpCom8,
955 opAndType{OCOM, TUINT8}: ssa.OpCom8,
956 opAndType{OCOM, TINT16}: ssa.OpCom16,
957 opAndType{OCOM, TUINT16}: ssa.OpCom16,
958 opAndType{OCOM, TINT32}: ssa.OpCom32,
959 opAndType{OCOM, TUINT32}: ssa.OpCom32,
960 opAndType{OCOM, TINT64}: ssa.OpCom64,
961 opAndType{OCOM, TUINT64}: ssa.OpCom64,
963 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
964 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
965 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
966 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
968 opAndType{OMUL, TINT8}: ssa.OpMul8,
969 opAndType{OMUL, TUINT8}: ssa.OpMul8,
970 opAndType{OMUL, TINT16}: ssa.OpMul16,
971 opAndType{OMUL, TUINT16}: ssa.OpMul16,
972 opAndType{OMUL, TINT32}: ssa.OpMul32,
973 opAndType{OMUL, TUINT32}: ssa.OpMul32,
974 opAndType{OMUL, TINT64}: ssa.OpMul64,
975 opAndType{OMUL, TUINT64}: ssa.OpMul64,
976 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
977 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
979 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
980 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
982 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
983 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
984 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
985 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
986 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
987 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
989 opAndType{ODIV, TINT8}: ssa.OpDiv8,
990 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
991 opAndType{ODIV, TINT16}: ssa.OpDiv16,
992 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
993 opAndType{ODIV, TINT32}: ssa.OpDiv32,
994 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
995 opAndType{ODIV, TINT64}: ssa.OpDiv64,
996 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
998 opAndType{OMOD, TINT8}: ssa.OpMod8,
999 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1000 opAndType{OMOD, TINT16}: ssa.OpMod16,
1001 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1002 opAndType{OMOD, TINT32}: ssa.OpMod32,
1003 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1004 opAndType{OMOD, TINT64}: ssa.OpMod64,
1005 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1007 opAndType{OAND, TINT8}: ssa.OpAnd8,
1008 opAndType{OAND, TUINT8}: ssa.OpAnd8,
1009 opAndType{OAND, TINT16}: ssa.OpAnd16,
1010 opAndType{OAND, TUINT16}: ssa.OpAnd16,
1011 opAndType{OAND, TINT32}: ssa.OpAnd32,
1012 opAndType{OAND, TUINT32}: ssa.OpAnd32,
1013 opAndType{OAND, TINT64}: ssa.OpAnd64,
1014 opAndType{OAND, TUINT64}: ssa.OpAnd64,
1016 opAndType{OOR, TINT8}: ssa.OpOr8,
1017 opAndType{OOR, TUINT8}: ssa.OpOr8,
1018 opAndType{OOR, TINT16}: ssa.OpOr16,
1019 opAndType{OOR, TUINT16}: ssa.OpOr16,
1020 opAndType{OOR, TINT32}: ssa.OpOr32,
1021 opAndType{OOR, TUINT32}: ssa.OpOr32,
1022 opAndType{OOR, TINT64}: ssa.OpOr64,
1023 opAndType{OOR, TUINT64}: ssa.OpOr64,
1025 opAndType{OXOR, TINT8}: ssa.OpXor8,
1026 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1027 opAndType{OXOR, TINT16}: ssa.OpXor16,
1028 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1029 opAndType{OXOR, TINT32}: ssa.OpXor32,
1030 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1031 opAndType{OXOR, TINT64}: ssa.OpXor64,
1032 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1034 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1035 opAndType{OEQ, TINT8}: ssa.OpEq8,
1036 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1037 opAndType{OEQ, TINT16}: ssa.OpEq16,
1038 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1039 opAndType{OEQ, TINT32}: ssa.OpEq32,
1040 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1041 opAndType{OEQ, TINT64}: ssa.OpEq64,
1042 opAndType{OEQ, TUINT64}: ssa.OpEq64,
1043 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1044 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
1045 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1046 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1047 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
1048 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
1049 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1050 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
1051 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1052 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
1054 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1055 opAndType{ONE, TINT8}: ssa.OpNeq8,
1056 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1057 opAndType{ONE, TINT16}: ssa.OpNeq16,
1058 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1059 opAndType{ONE, TINT32}: ssa.OpNeq32,
1060 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1061 opAndType{ONE, TINT64}: ssa.OpNeq64,
1062 opAndType{ONE, TUINT64}: ssa.OpNeq64,
1063 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1064 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
1065 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1066 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1067 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
1068 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
1069 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1070 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
1071 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1072 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
1074 opAndType{OLT, TINT8}: ssa.OpLess8,
1075 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1076 opAndType{OLT, TINT16}: ssa.OpLess16,
1077 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1078 opAndType{OLT, TINT32}: ssa.OpLess32,
1079 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1080 opAndType{OLT, TINT64}: ssa.OpLess64,
1081 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1082 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1083 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
1085 opAndType{OGT, TINT8}: ssa.OpGreater8,
1086 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1087 opAndType{OGT, TINT16}: ssa.OpGreater16,
1088 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1089 opAndType{OGT, TINT32}: ssa.OpGreater32,
1090 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1091 opAndType{OGT, TINT64}: ssa.OpGreater64,
1092 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1093 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1094 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
1096 opAndType{OLE, TINT8}: ssa.OpLeq8,
1097 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1098 opAndType{OLE, TINT16}: ssa.OpLeq16,
1099 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1100 opAndType{OLE, TINT32}: ssa.OpLeq32,
1101 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1102 opAndType{OLE, TINT64}: ssa.OpLeq64,
1103 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1104 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1105 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
1107 opAndType{OGE, TINT8}: ssa.OpGeq8,
1108 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1109 opAndType{OGE, TINT16}: ssa.OpGeq16,
1110 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1111 opAndType{OGE, TINT32}: ssa.OpGeq32,
1112 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1113 opAndType{OGE, TINT64}: ssa.OpGeq64,
1114 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1115 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1116 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
1118 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1119 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1120 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1121 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
1123 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
1126 func (s *state) concreteEtype(t *Type) EType {
1132 if s.config.IntSize == 8 {
1137 if s.config.IntSize == 8 {
1142 if s.config.PtrSize == 8 {
1149 func (s *state) ssaOp(op Op, t *Type) ssa.Op {
1150 etype := s.concreteEtype(t)
1151 x, ok := opToSSA[opAndType{op, etype}]
1153 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
1158 func floatForComplex(t *Type) *Type {
1160 return Types[TFLOAT32]
1162 return Types[TFLOAT64]
1166 type opAndTwoTypes struct {
1172 type twoTypes struct {
1177 type twoOpsAndType struct {
1180 intermediateType EType
1183 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1185 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1186 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1187 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1188 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1190 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1191 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1192 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1193 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1195 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1196 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1197 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1198 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1200 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1201 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1202 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1203 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1205 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1206 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1207 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1208 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1210 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1211 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1212 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1213 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1215 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1216 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1217 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1218 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1220 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1221 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1222 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1223 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1226 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1227 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1228 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1229 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1232 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1233 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1234 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1235 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1236 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1237 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1238 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1239 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1240 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1242 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1243 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1244 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1245 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1246 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1247 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1248 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1249 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1251 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1252 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1253 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1254 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1255 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1256 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1257 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1258 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1260 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1261 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1262 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1263 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1264 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1265 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1266 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1267 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1269 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1270 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1271 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1272 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1273 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1274 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1275 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1276 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1278 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1279 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1280 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1281 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1282 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1283 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1284 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1285 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1287 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1288 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1289 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1290 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1291 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1292 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1293 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1294 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1296 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1297 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1298 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1299 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1300 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1301 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1302 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1303 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1306 func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
1307 etype1 := s.concreteEtype(t)
1308 etype2 := s.concreteEtype(u)
1309 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1311 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
1316 func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
1317 etype1 := s.concreteEtype(t)
1318 x, ok := opToSSA[opAndType{op, etype1}]
1320 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
1325 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
1326 func (s *state) expr(n *Node) *ssa.Value {
1327 s.pushLine(n.Lineno)
1333 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
1334 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
1336 addr := s.addr(n, false)
1337 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
1339 if n.Class == PFUNC {
1340 // "value" of a function is the address of the function's closure
1341 sym := funcsym(n.Sym)
1342 aux := &ssa.ExternSymbol{n.Type, sym}
1343 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
1346 return s.variable(n, n.Type)
1348 addr := s.addr(n, false)
1349 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1351 addr := s.addr(n, false)
1352 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1354 switch n.Val().Ctype() {
1356 i := Mpgetfix(n.Val().U.(*Mpint))
1357 switch n.Type.Size() {
1359 return s.constInt8(n.Type, int8(i))
1361 return s.constInt16(n.Type, int16(i))
1363 return s.constInt32(n.Type, int32(i))
1365 return s.constInt64(n.Type, i)
1367 s.Fatalf("bad integer size %d", n.Type.Size())
1371 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1373 v := s.constBool(n.Val().U.(bool))
1374 // For some reason the frontend gets the line numbers of
1375 // CTBOOL literals totally wrong. Fix it here by grabbing
1376 // the line number of the enclosing AST node.
1377 if len(s.line) >= 2 {
1378 v.Line = s.line[len(s.line)-2]
1385 return s.entryNewValue0(ssa.OpConstSlice, t)
1386 case t.IsInterface():
1387 return s.entryNewValue0(ssa.OpConstInterface, t)
1389 return s.entryNewValue0(ssa.OpConstNil, t)
1392 f := n.Val().U.(*Mpflt)
1393 switch n.Type.Size() {
1395 return s.constFloat32(n.Type, mpgetflt32(f))
1397 return s.constFloat64(n.Type, mpgetflt(f))
1399 s.Fatalf("bad float size %d", n.Type.Size())
1403 c := n.Val().U.(*Mpcplx)
1406 switch n.Type.Size() {
1409 pt := Types[TFLOAT32]
1410 return s.newValue2(ssa.OpComplexMake, n.Type,
1411 s.constFloat32(pt, mpgetflt32(r)),
1412 s.constFloat32(pt, mpgetflt32(i)))
1416 pt := Types[TFLOAT64]
1417 return s.newValue2(ssa.OpComplexMake, n.Type,
1418 s.constFloat64(pt, mpgetflt(r)),
1419 s.constFloat64(pt, mpgetflt(i)))
1422 s.Fatalf("bad float size %d", n.Type.Size())
1427 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
1434 // Assume everything will work out, so set up our return value.
1435 // Anything interesting that happens from here is a fatal.
1438 // Special case for not confusing GC and liveness.
1439 // We don't want pointers accidentally classified
1440 // as not-pointers or vice-versa because of copy
1442 if to.IsPtr() != from.IsPtr() {
1443 return s.newValue2(ssa.OpConvert, to, x, s.mem())
1446 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1449 if to.Etype == TFUNC && from.IsPtr() {
1453 // named <--> unnamed type or typed <--> untyped const
1454 if from.Etype == to.Etype {
1458 // unsafe.Pointer <--> *T
1459 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1465 if from.Width != to.Width {
1466 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1469 if etypesign(from.Etype) != etypesign(to.Etype) {
1470 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
1475 // These appear to be fine, but they fail the
1476 // integer constraint below, so okay them here.
1477 // Sample non-integer conversion: map[string]string -> *uint8
1481 if etypesign(from.Etype) == 0 {
1482 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1486 // integer, same width, same sign
1491 ft := n.Left.Type // from type
1492 tt := n.Type // to type
1493 if ft.IsInteger() && tt.IsInteger() {
1495 if tt.Size() == ft.Size() {
1497 } else if tt.Size() < ft.Size() {
1499 switch 10*ft.Size() + tt.Size() {
1501 op = ssa.OpTrunc16to8
1503 op = ssa.OpTrunc32to8
1505 op = ssa.OpTrunc32to16
1507 op = ssa.OpTrunc64to8
1509 op = ssa.OpTrunc64to16
1511 op = ssa.OpTrunc64to32
1513 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1515 } else if ft.IsSigned() {
1517 switch 10*ft.Size() + tt.Size() {
1519 op = ssa.OpSignExt8to16
1521 op = ssa.OpSignExt8to32
1523 op = ssa.OpSignExt8to64
1525 op = ssa.OpSignExt16to32
1527 op = ssa.OpSignExt16to64
1529 op = ssa.OpSignExt32to64
1531 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1535 switch 10*ft.Size() + tt.Size() {
1537 op = ssa.OpZeroExt8to16
1539 op = ssa.OpZeroExt8to32
1541 op = ssa.OpZeroExt8to64
1543 op = ssa.OpZeroExt16to32
1545 op = ssa.OpZeroExt16to64
1547 op = ssa.OpZeroExt32to64
1549 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1552 return s.newValue1(op, n.Type, x)
1555 if ft.IsFloat() || tt.IsFloat() {
1556 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1558 s.Fatalf("weird float conversion %s -> %s", ft, tt)
1560 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1562 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1563 // normal case, not tripping over unsigned 64
1564 if op1 == ssa.OpCopy {
1565 if op2 == ssa.OpCopy {
1568 return s.newValue1(op2, n.Type, x)
1570 if op2 == ssa.OpCopy {
1571 return s.newValue1(op1, n.Type, x)
1573 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1575 // Tricky 64-bit unsigned cases.
1577 // therefore tt is float32 or float64, and ft is also unsigned
1579 return s.uint64Tofloat32(n, x, ft, tt)
1582 return s.uint64Tofloat64(n, x, ft, tt)
1584 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
1586 // therefore ft is float32 or float64, and tt is unsigned integer
1588 return s.float32ToUint64(n, x, ft, tt)
1591 return s.float64ToUint64(n, x, ft, tt)
1593 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1597 if ft.IsComplex() && tt.IsComplex() {
1599 if ft.Size() == tt.Size() {
1601 } else if ft.Size() == 8 && tt.Size() == 16 {
1602 op = ssa.OpCvt32Fto64F
1603 } else if ft.Size() == 16 && tt.Size() == 8 {
1604 op = ssa.OpCvt64Fto32F
1606 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1608 ftp := floatForComplex(ft)
1609 ttp := floatForComplex(tt)
1610 return s.newValue2(ssa.OpComplexMake, tt,
1611 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1612 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1615 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
1619 res, _ := s.dottype(n, false)
1623 case OLT, OEQ, ONE, OLE, OGE, OGT:
1625 b := s.expr(n.Right)
1626 if n.Left.Type.IsComplex() {
1627 pt := floatForComplex(n.Left.Type)
1628 op := s.ssaOp(OEQ, pt)
1629 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1630 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1631 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1636 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1638 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1641 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
1644 b := s.expr(n.Right)
1645 if n.Type.IsComplex() {
1646 mulop := ssa.OpMul64F
1647 addop := ssa.OpAdd64F
1648 subop := ssa.OpSub64F
1649 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1650 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1652 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1653 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1654 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1655 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1657 if pt != wt { // Widen for calculation
1658 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1659 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1660 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1661 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1664 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1665 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1667 if pt != wt { // Narrow to store back
1668 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1669 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1672 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1674 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1678 b := s.expr(n.Right)
1679 if n.Type.IsComplex() {
1680 // TODO this is not executed because the front-end substitutes a runtime call.
1681 // That probably ought to change; with modest optimization the widen/narrow
1682 // conversions could all be elided in larger expression trees.
1683 mulop := ssa.OpMul64F
1684 addop := ssa.OpAdd64F
1685 subop := ssa.OpSub64F
1686 divop := ssa.OpDiv64F
1687 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1688 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1690 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1691 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1692 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1693 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1695 if pt != wt { // Widen for calculation
1696 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1697 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1698 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1699 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1702 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1703 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1704 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1706 // TODO not sure if this is best done in wide precision or narrow
1707 // Double-rounding might be an issue.
1708 // Note that the pre-SSA implementation does the entire calculation
1709 // in wide format, so wide is compatible.
1710 xreal = s.newValue2(divop, wt, xreal, denom)
1711 ximag = s.newValue2(divop, wt, ximag, denom)
1713 if pt != wt { // Narrow to store back
1714 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1715 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1717 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1719 if n.Type.IsFloat() {
1720 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1722 // do a size-appropriate check for zero
1723 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1724 s.check(cmp, panicdivide)
1725 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1729 b := s.expr(n.Right)
1730 // do a size-appropriate check for zero
1731 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1732 s.check(cmp, panicdivide)
1733 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1736 b := s.expr(n.Right)
1737 if n.Type.IsComplex() {
1738 pt := floatForComplex(n.Type)
1739 op := s.ssaOp(n.Op, pt)
1740 return s.newValue2(ssa.OpComplexMake, n.Type,
1741 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1742 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1744 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1745 case OAND, OOR, OHMUL, OXOR:
1747 b := s.expr(n.Right)
1748 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1751 b := s.expr(n.Right)
1752 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
1756 if i <= 0 || i >= n.Type.Size()*8 {
1757 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1759 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
1760 case OANDAND, OOROR:
1761 // To implement OANDAND (and OOROR), we introduce a
1762 // new temporary variable to hold the result. The
1763 // variable is associated with the OANDAND node in the
1764 // s.vars table (normally variables are only
1765 // associated with ONAME nodes). We convert
1772 // Using var in the subsequent block introduces the
1773 // necessary phi variable.
1774 el := s.expr(n.Left)
1778 b.Kind = ssa.BlockIf
1780 // In theory, we should set b.Likely here based on context.
1781 // However, gc only gives us likeliness hints
1782 // in a single place, for plain OIF statements,
1783 // and passing around context is finnicky, so don't bother for now.
1785 bRight := s.f.NewBlock(ssa.BlockPlain)
1786 bResult := s.f.NewBlock(ssa.BlockPlain)
1787 if n.Op == OANDAND {
1789 b.AddEdgeTo(bResult)
1790 } else if n.Op == OOROR {
1791 b.AddEdgeTo(bResult)
1795 s.startBlock(bRight)
1796 er := s.expr(n.Right)
1800 b.AddEdgeTo(bResult)
1802 s.startBlock(bResult)
1803 return s.variable(n, Types[TBOOL])
1806 i := s.expr(n.Right)
1807 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
1812 if n.Type.IsComplex() {
1813 tp := floatForComplex(n.Type)
1814 negop := s.ssaOp(n.Op, tp)
1815 return s.newValue2(ssa.OpComplexMake, n.Type,
1816 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1817 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1819 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1820 case ONOT, OCOM, OSQRT:
1822 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1825 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
1827 return s.expr(n.Left)
1830 return s.addr(n.Left, n.Bounded)
1833 if int(n.Reg) != Thearch.REGSP {
1834 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1837 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1838 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1843 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1849 return s.newValue1I(ssa.OpStructSelect, n.Type, fieldIdx(n), v)
1851 p := s.addr(n, false)
1852 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1857 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
1858 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1862 case n.Left.Type.IsString():
1864 i := s.expr(n.Right)
1865 i = s.extendIndex(i)
1867 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1868 s.boundsCheck(i, len)
1870 ptrtyp := Ptrto(Types[TUINT8])
1871 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1872 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1873 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1874 case n.Left.Type.IsSlice():
1875 p := s.addr(n, false)
1876 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1877 case n.Left.Type.IsArray():
1878 // TODO: fix when we can SSA arrays of length 1.
1879 p := s.addr(n, false)
1880 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1882 s.Fatalf("bad type for index %v", n.Left.Type)
1888 case n.Left.Type.IsSlice():
1889 op := ssa.OpSliceLen
1893 return s.newValue1(op, Types[TINT], s.expr(n.Left))
1894 case n.Left.Type.IsString(): // string; not reachable for OCAP
1895 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
1896 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1897 return s.referenceTypeBuiltin(n, s.expr(n.Left))
1899 return s.constInt(Types[TINT], n.Left.Type.Bound)
1904 if n.Left.Type.IsSlice() {
1905 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1907 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1912 return s.newValue1(ssa.OpITab, n.Type, a)
1915 tab := s.expr(n.Left)
1916 data := s.expr(n.Right)
1917 // The frontend allows putting things like struct{*byte} in
1918 // the data portion of an eface. But we don't want struct{*byte}
1919 // as a register type because (among other reasons) the liveness
1920 // analysis is confused by the "fat" variables that result from
1921 // such types being spilled.
1922 // So here we ensure that we are selecting the underlying pointer
1923 // when we build an eface.
1924 // TODO: get rid of this now that structs can be SSA'd?
1925 for !data.Type.IsPtr() {
1927 case data.Type.IsArray():
1928 data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
1929 case data.Type.IsStruct():
1930 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1931 f := data.Type.FieldType(i)
1933 // eface type could also be struct{p *byte; q [0]int}
1936 data = s.newValue1I(ssa.OpStructSelect, f, i, data)
1940 s.Fatalf("type being put into an eface isn't a pointer")
1943 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1945 case OSLICE, OSLICEARR:
1948 if n.Right.Left != nil {
1949 i = s.extendIndex(s.expr(n.Right.Left))
1951 if n.Right.Right != nil {
1952 j = s.extendIndex(s.expr(n.Right.Right))
1954 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1955 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1959 if n.Right.Left != nil {
1960 i = s.extendIndex(s.expr(n.Right.Left))
1962 if n.Right.Right != nil {
1963 j = s.extendIndex(s.expr(n.Right.Right))
1965 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1966 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1967 case OSLICE3, OSLICE3ARR:
1970 if n.Right.Left != nil {
1971 i = s.extendIndex(s.expr(n.Right.Left))
1973 j := s.extendIndex(s.expr(n.Right.Right.Left))
1974 k := s.extendIndex(s.expr(n.Right.Right.Right))
1975 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1976 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1978 case OCALLFUNC, OCALLINTER, OCALLMETH:
1979 a := s.call(n, callNormal)
1980 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
1983 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
1986 // append(s, e1, e2, e3). Compile like:
1988 // newlen := len + 3
1989 // if newlen > s.cap {
1990 // ptr,_,cap = growslice(s, newlen)
1993 // *(ptr+len+1) = e2
1994 // *(ptr+len+2) = e3
1995 // makeslice(ptr,newlen,cap)
2001 slice := s.expr(n.List.N)
2003 // Allocate new blocks
2004 grow := s.f.NewBlock(ssa.BlockPlain)
2005 assign := s.f.NewBlock(ssa.BlockPlain)
2007 // Decide if we need to grow
2008 nargs := int64(count(n.List) - 1)
2009 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2010 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2011 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2012 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2013 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
2017 b.Kind = ssa.BlockIf
2018 b.Likely = ssa.BranchUnlikely
2025 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
2027 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
2029 s.vars[&ptrVar] = r[0]
2030 // Note: we don't need to read r[1], the result's length. It will be nl.
2031 // (or maybe we should, we just have to spill/restore nl otherwise?)
2032 s.vars[&capVar] = r[2]
2036 // assign new elements to slots
2037 s.startBlock(assign)
2040 args := make([]*ssa.Value, 0, nargs)
2041 store := make([]bool, 0, nargs)
2042 for l := n.List.Next; l != nil; l = l.Next {
2043 if canSSAType(l.N.Type) {
2044 args = append(args, s.expr(l.N))
2045 store = append(store, true)
2047 args = append(args, s.addr(l.N, false))
2048 store = append(store, false)
2052 p = s.variable(&ptrVar, pt) // generates phi for ptr
2053 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
2054 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
2055 // TODO: just one write barrier call for all of these writes?
2056 // TODO: maybe just one writeBarrier.enabled check?
2057 for i, arg := range args {
2058 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
2060 if haspointers(et) {
2061 s.insertWBstore(et, addr, arg, n.Lineno)
2063 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2066 if haspointers(et) {
2067 s.insertWBmove(et, addr, arg, n.Lineno)
2069 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2075 delete(s.vars, &ptrVar)
2076 delete(s.vars, &capVar)
2077 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2080 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
2085 // condBranch evaluates the boolean expression cond and branches to yes
2086 // if cond is true and no if cond is false.
2087 // This function is intended to handle && and || better than just calling
2088 // s.expr(cond) and branching on the result.
2089 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2090 if cond.Op == OANDAND {
2091 mid := s.f.NewBlock(ssa.BlockPlain)
2092 s.stmtList(cond.Ninit)
2093 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2095 s.condBranch(cond.Right, yes, no, likely)
2097 // Note: if likely==1, then both recursive calls pass 1.
2098 // If likely==-1, then we don't have enough information to decide
2099 // whether the first branch is likely or not. So we pass 0 for
2100 // the likeliness of the first branch.
2101 // TODO: have the frontend give us branch prediction hints for
2102 // OANDAND and OOROR nodes (if it ever has such info).
2104 if cond.Op == OOROR {
2105 mid := s.f.NewBlock(ssa.BlockPlain)
2106 s.stmtList(cond.Ninit)
2107 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2109 s.condBranch(cond.Right, yes, no, likely)
2111 // Note: if likely==-1, then both recursive calls pass -1.
2112 // If likely==1, then we don't have enough info to decide
2113 // the likelihood of the first branch.
2115 if cond.Op == ONOT {
2116 s.stmtList(cond.Ninit)
2117 s.condBranch(cond.Left, no, yes, -likely)
2122 b.Kind = ssa.BlockIf
2124 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2129 // assign does left = right.
2130 // Right has already been evaluated to ssa, left has not.
2131 // If deref is true, then we do left = *right instead (and right has already been nil-checked).
2132 // If deref is true and right == nil, just do left = 0.
2133 // Include a write barrier if wb is true.
2134 func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32) {
2135 if left.Op == ONAME && isblank(left) {
2142 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2144 if left.Op == ODOT {
2145 // We're assigning to a field of an ssa-able value.
2146 // We need to build a new structure with the new value for the
2147 // field we're assigning and the old values for the other fields.
2149 // type T struct {a, b, c int}
2152 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2154 // Grab information about the structure type.
2157 idx := fieldIdx(left)
2159 // Grab old value of structure.
2160 old := s.expr(left.Left)
2162 // Make new structure.
2163 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2165 // Add fields as args.
2166 for i := int64(0); i < nf; i++ {
2170 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), i, old))
2174 // Recursively assign the new value we've made to the base of the dot op.
2175 s.assign(left.Left, new, false, false, line)
2176 // TODO: do we need to update named values here?
2179 // Update variable assignment.
2180 s.vars[left] = right
2181 s.addNamedValue(left, right)
2184 // Left is not ssa-able. Compute its address.
2185 addr := s.addr(left, false)
2186 if left.Op == ONAME {
2187 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2190 // Treat as a mem->mem move.
2192 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2196 s.insertWBmove(t, addr, right, line)
2199 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2202 // Treat as a store.
2204 s.insertWBstore(t, addr, right, line)
2207 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
2210 // zeroVal returns the zero value for type t.
2211 func (s *state) zeroVal(t *Type) *ssa.Value {
2216 return s.constInt8(t, 0)
2218 return s.constInt16(t, 0)
2220 return s.constInt32(t, 0)
2222 return s.constInt64(t, 0)
2224 s.Fatalf("bad sized integer type %s", t)
2229 return s.constFloat32(t, 0)
2231 return s.constFloat64(t, 0)
2233 s.Fatalf("bad sized float type %s", t)
2238 z := s.constFloat32(Types[TFLOAT32], 0)
2239 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2241 z := s.constFloat64(Types[TFLOAT64], 0)
2242 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2244 s.Fatalf("bad sized complex type %s", t)
2248 return s.entryNewValue0A(ssa.OpConstString, t, "")
2250 return s.entryNewValue0(ssa.OpConstNil, t)
2252 return s.constBool(false)
2253 case t.IsInterface():
2254 return s.entryNewValue0(ssa.OpConstInterface, t)
2256 return s.entryNewValue0(ssa.OpConstSlice, t)
2259 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
2260 for i := int64(0); i < n; i++ {
2261 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2265 s.Unimplementedf("zero for type %v not implemented", t)
2272 callNormal callKind = iota
2277 // Calls the function n using the specified call type.
2278 // Returns the address of the return value (or nil if none).
2279 func (s *state) call(n *Node, k callKind) *ssa.Value {
2280 var sym *Sym // target symbol (if static)
2281 var closure *ssa.Value // ptr to closure to run (if dynamic)
2282 var codeptr *ssa.Value // ptr to target code (if dynamic)
2283 var rcvr *ssa.Value // receiver to set
2287 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2291 closure = s.expr(fn)
2293 if fn.Op != ODOTMETH {
2294 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2296 if fn.Right.Op != ONAME {
2297 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2299 if k == callNormal {
2305 closure = s.expr(&n2)
2306 // Note: receiver is already assigned in n.List, so we don't
2307 // want to set it here.
2309 if fn.Op != ODOTINTER {
2310 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2312 i := s.expr(fn.Left)
2313 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2314 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2315 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2316 if k == callNormal {
2317 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2321 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2324 stksize := fn.Type.Argwid // includes receiver
2326 // Run all argument assignments. The arg slots have already
2327 // been offset by the appropriate amount (+2*widthptr for go/defer,
2328 // +widthptr for interface calls).
2329 // For OCALLMETH, the receiver is set in these statements.
2332 // Set receiver (for interface calls)
2334 argStart := Ctxt.FixedFrameSize()
2335 if k != callNormal {
2336 argStart += int64(2 * Widthptr)
2338 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
2339 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
2343 if k != callNormal {
2344 // Write argsize and closure (args to Newproc/Deferproc).
2345 argsize := s.constInt32(Types[TUINT32], int32(stksize))
2346 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
2347 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
2348 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
2349 stksize += 2 * int64(Widthptr)
2353 bNext := s.f.NewBlock(ssa.BlockPlain)
2356 case k == callDefer:
2357 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2359 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2360 case closure != nil:
2361 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2362 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2363 case codeptr != nil:
2364 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2366 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2368 Fatalf("bad call type %s %v", opnames[n.Op], n)
2370 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2372 // Finish call block
2373 s.vars[&memVar] = call
2375 b.Kind = ssa.BlockCall
2379 // Start exit block, find address of result.
2382 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2383 if fp == nil || k != callNormal {
2384 // call has no return value. Continue with the next statement.
2387 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
2390 // etypesign returns the signed-ness of e, for integer/pointer etypes.
2391 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
2392 func etypesign(e EType) int8 {
2394 case TINT8, TINT16, TINT32, TINT64, TINT:
2396 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2402 // lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2403 // This improves the effectiveness of cse by using the same Aux values for the
2405 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2408 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2409 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2410 // these are the only valid types
2413 if lsym, ok := s.varsyms[n]; ok {
2421 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
2422 // The value that the returned Value represents is guaranteed to be non-nil.
2423 // If bounded is true then this address does not require a nil check for its operand
2424 // even if that would otherwise be implied.
2425 func (s *state) addr(n *Node, bounded bool) *ssa.Value {
2432 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
2433 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
2434 // TODO: Make OpAddr use AuxInt as well as Aux.
2436 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2445 if n.String() == ".fp" {
2446 // Special arg that points to the frame pointer.
2447 // (Used by the race detector, others?)
2448 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2449 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2451 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2454 // We need to regenerate the address of autos
2455 // at every use. This prevents LEA instructions
2456 // from occurring before the corresponding VarDef
2457 // op and confusing the liveness analysis into thinking
2458 // the variable is live at function entry.
2459 // TODO: I'm not sure if this really works or we're just
2460 // getting lucky. We might need a real dependency edge
2461 // between vardef and addr ops.
2462 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
2463 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2464 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
2465 // ensure that we reuse symbols for out parameters so
2466 // that cse works on their addresses
2467 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2468 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2469 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
2470 return s.expr(n.Name.Heapaddr)
2472 s.Unimplementedf("variable address class %v not implemented", n.Class)
2476 // indirect off a register
2477 // used for storing/loading arguments/returns to/from callees
2478 if int(n.Reg) != Thearch.REGSP {
2479 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2482 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
2484 if n.Left.Type.IsSlice() {
2486 i := s.expr(n.Right)
2487 i = s.extendIndex(i)
2488 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
2490 s.boundsCheck(i, len)
2492 p := s.newValue1(ssa.OpSlicePtr, t, a)
2493 return s.newValue2(ssa.OpPtrIndex, t, p, i)
2495 a := s.addr(n.Left, bounded)
2496 i := s.expr(n.Right)
2497 i = s.extendIndex(i)
2498 len := s.constInt(Types[TINT], n.Left.Type.Bound)
2500 s.boundsCheck(i, len)
2502 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
2511 p := s.addr(n.Left, bounded)
2512 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2518 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2520 return s.newValue2(ssa.OpAddPtr, t,
2521 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
2522 s.constInt(Types[TINT], n.Xoffset))
2525 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2526 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2529 // Recover original offset to address passed-in param value.
2531 original_p.Xoffset = n.Xoffset
2532 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
2533 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2535 addr := s.addr(n.Left, bounded)
2536 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
2537 case OCALLFUNC, OCALLINTER, OCALLMETH:
2538 return s.call(n, callNormal)
2541 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
2546 // canSSA reports whether n is SSA-able.
2547 // n must be an ONAME (or an ODOT sequence with an ONAME base).
2548 func canSSA(n *Node) bool {
2558 if n.Class&PHEAP != 0 {
2562 case PEXTERN, PPARAMOUT, PPARAMREF:
2565 if n.Class == PPARAM && n.String() == ".this" {
2566 // wrappers generated by genwrapper need to update
2567 // the .this pointer in place.
2570 return canSSAType(n.Type)
2571 // TODO: try to make more variables SSAable?
2574 // canSSA reports whether variables of type t are SSA-able.
2575 func canSSAType(t *Type) bool {
2577 if t.Width > int64(4*Widthptr) {
2578 // 4*Widthptr is an arbitrary constant. We want it
2579 // to be at least 3*Widthptr so slices can be registerized.
2580 // Too big and we'll introduce too much register pressure.
2588 // We can't do arrays because dynamic indexing is
2589 // not supported on SSA variables.
2590 // TODO: maybe allow if length is <=1? All indexes
2591 // are constant? Might be good for the arrays
2592 // introduced by the compiler for variadic functions.
2595 if countfield(t) > ssa.MaxStruct {
2598 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2599 if !canSSAType(t1.Type) {
2609 // nilCheck generates nil pointer checking code.
2610 // Starts a new block on return, unless nil checks are disabled.
2611 // Used only for automatically inserted nil checks,
2612 // not for user code like 'x != nil'.
2613 func (s *state) nilCheck(ptr *ssa.Value) {
2614 if Disable_checknil != 0 {
2617 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
2619 b.Kind = ssa.BlockCheck
2621 bNext := s.f.NewBlock(ssa.BlockPlain)
2626 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2627 // Starts a new block on return.
2628 func (s *state) boundsCheck(idx, len *ssa.Value) {
2629 if Debug['B'] != 0 {
2632 // TODO: convert index to full width?
2633 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2636 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
2637 s.check(cmp, Panicindex)
2640 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2641 // Starts a new block on return.
2642 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2643 if Debug['B'] != 0 {
2646 // TODO: convert index to full width?
2647 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2650 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
2651 s.check(cmp, panicslice)
2654 // If cmp (a bool) is true, panic using the given function.
2655 func (s *state) check(cmp *ssa.Value, fn *Node) {
2657 b.Kind = ssa.BlockIf
2659 b.Likely = ssa.BranchLikely
2660 bNext := s.f.NewBlock(ssa.BlockPlain)
2661 line := s.peekLine()
2662 bPanic := s.panics[funcLine{fn, line}]
2664 bPanic = s.f.NewBlock(ssa.BlockPlain)
2665 s.panics[funcLine{fn, line}] = bPanic
2666 s.startBlock(bPanic)
2667 // The panic call takes/returns memory to ensure that the right
2668 // memory state is observed if the panic happens.
2669 s.rtcall(fn, false, nil)
2676 // rtcall issues a call to the given runtime function fn with the listed args.
2677 // Returns a slice of results of the given result types.
2678 // The call is added to the end of the current block.
2679 // If returns is false, the block is marked as an exit block.
2680 // If returns is true, the block is marked as a call block. A new block
2681 // is started to load the return values.
2682 func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2683 // Write args to the stack
2684 var off int64 // TODO: arch-dependent starting offset?
2685 for _, arg := range args {
2687 off = Rnd(off, t.Alignment())
2690 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2693 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2696 off = Rnd(off, int64(Widthptr))
2699 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2700 s.vars[&memVar] = call
2705 b.Kind = ssa.BlockExit
2708 if len(results) > 0 {
2709 Fatalf("panic call can't have results")
2713 b.Kind = ssa.BlockCall
2715 bNext := s.f.NewBlock(ssa.BlockPlain)
2720 res := make([]*ssa.Value, len(results))
2721 for i, t := range results {
2722 off = Rnd(off, t.Alignment())
2725 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2727 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2730 off = Rnd(off, int64(Widthptr))
2732 // Remember how much callee stack space we needed.
2738 // insertWBmove inserts the assignment *left = *right including a write barrier.
2739 // t is the type being assigned.
2740 func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
2741 // if writeBarrier.enabled {
2742 // typedmemmove(&t, left, right)
2746 bThen := s.f.NewBlock(ssa.BlockPlain)
2747 bElse := s.f.NewBlock(ssa.BlockPlain)
2748 bEnd := s.f.NewBlock(ssa.BlockPlain)
2750 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2751 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2752 // TODO: select the .enabled field. It is currently first, so not needed for now.
2753 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2755 b.Kind = ssa.BlockIf
2756 b.Likely = ssa.BranchUnlikely
2762 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
2763 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2764 s.endBlock().AddEdgeTo(bEnd)
2767 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2768 s.endBlock().AddEdgeTo(bEnd)
2773 Warnl(int(line), "write barrier")
2777 // insertWBstore inserts the assignment *left = right including a write barrier.
2778 // t is the type being assigned.
2779 func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32) {
2780 // store scalar fields
2781 // if writeBarrier.enabled {
2782 // writebarrierptr for pointer fields
2784 // store pointer fields
2787 s.storeTypeScalars(t, left, right)
2789 bThen := s.f.NewBlock(ssa.BlockPlain)
2790 bElse := s.f.NewBlock(ssa.BlockPlain)
2791 bEnd := s.f.NewBlock(ssa.BlockPlain)
2793 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2794 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2795 // TODO: select the .enabled field. It is currently first, so not needed for now.
2796 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2798 b.Kind = ssa.BlockIf
2799 b.Likely = ssa.BranchUnlikely
2804 // Issue write barriers for pointer writes.
2806 s.storeTypePtrsWB(t, left, right)
2807 s.endBlock().AddEdgeTo(bEnd)
2809 // Issue regular stores for pointer writes.
2811 s.storeTypePtrs(t, left, right)
2812 s.endBlock().AddEdgeTo(bEnd)
2817 Warnl(int(line), "write barrier")
2821 // do *left = right for all scalar (non-pointer) parts of t.
2822 func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value) {
2824 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
2825 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
2826 case t.IsPtr() || t.IsMap() || t.IsChan():
2827 // no scalar fields.
2829 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
2830 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2831 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2833 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
2834 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
2835 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2836 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2837 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
2838 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
2839 case t.IsInterface():
2840 // itab field doesn't need a write barrier (even though it is a pointer).
2841 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
2842 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
2845 for i := int64(0); i < n; i++ {
2846 ft := t.FieldType(i)
2847 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2848 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2849 s.storeTypeScalars(ft.(*Type), addr, val)
2852 s.Fatalf("bad write barrier type %s", t)
2856 // do *left = right for all pointer parts of t.
2857 func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
2859 case t.IsPtr() || t.IsMap() || t.IsChan():
2860 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
2862 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2863 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2865 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2866 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2867 case t.IsInterface():
2868 // itab field is treated as a scalar.
2869 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2870 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2871 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
2874 for i := int64(0); i < n; i++ {
2875 ft := t.FieldType(i)
2876 if !haspointers(ft.(*Type)) {
2879 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2880 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2881 s.storeTypePtrs(ft.(*Type), addr, val)
2884 s.Fatalf("bad write barrier type %s", t)
2888 // do *left = right with a write barrier for all pointer parts of t.
2889 func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
2891 case t.IsPtr() || t.IsMap() || t.IsChan():
2892 s.rtcall(writebarrierptr, true, nil, left, right)
2894 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2895 s.rtcall(writebarrierptr, true, nil, left, ptr)
2897 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2898 s.rtcall(writebarrierptr, true, nil, left, ptr)
2899 case t.IsInterface():
2900 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2901 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2902 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
2905 for i := int64(0); i < n; i++ {
2906 ft := t.FieldType(i)
2907 if !haspointers(ft.(*Type)) {
2910 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2911 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2912 s.storeTypePtrsWB(ft.(*Type), addr, val)
2915 s.Fatalf("bad write barrier type %s", t)
2919 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2920 // i,j,k may be nil, in which case they are set to their default value.
2921 // t is a slice, ptr to array, or string type.
2922 func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2928 zero := s.constInt(Types[TINT], 0)
2932 ptrtype = Ptrto(elemtype)
2933 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2934 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2935 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2937 elemtype = Types[TUINT8]
2938 ptrtype = Ptrto(elemtype)
2939 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2940 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2943 if !t.Type.IsArray() {
2944 s.Fatalf("bad ptr to array in slice %v\n", t)
2946 elemtype = t.Type.Type
2947 ptrtype = Ptrto(elemtype)
2950 len = s.constInt(Types[TINT], t.Type.Bound)
2953 s.Fatalf("bad type in slice %v\n", t)
2956 // Set default values
2967 // Panic if slice indices are not in bounds.
2968 s.sliceBoundsCheck(i, j)
2970 s.sliceBoundsCheck(j, k)
2973 s.sliceBoundsCheck(k, cap)
2976 // Generate the following code assuming that indexes are in bounds.
2977 // The conditional is to make sure that we don't generate a slice
2978 // that points to the next object in memory.
2979 // rlen = (Sub64 j i)
2980 // rcap = (Sub64 k i)
2983 // p = (AddPtr ptr (Mul64 low (Const64 size)))
2985 // result = (SliceMake p size)
2986 subOp := s.ssaOp(OSUB, Types[TINT])
2987 neqOp := s.ssaOp(ONE, Types[TINT])
2988 mulOp := s.ssaOp(OMUL, Types[TINT])
2989 rlen := s.newValue2(subOp, Types[TINT], j, i)
2993 // Capacity of the result is unimportant. However, we use
2994 // rcap to test if we've generated a zero-length slice.
2995 // Use length of strings for that.
3000 rcap = s.newValue2(subOp, Types[TINT], k, i)
3003 s.vars[&ptrVar] = ptr
3005 // Generate code to test the resulting slice length.
3006 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
3009 b.Kind = ssa.BlockIf
3010 b.Likely = ssa.BranchLikely
3013 // Generate code for non-zero length slice case.
3014 nz := s.f.NewBlock(ssa.BlockPlain)
3018 if elemtype.Width == 1 {
3021 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
3023 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
3027 merge := s.f.NewBlock(ssa.BlockPlain)
3031 rptr := s.variable(&ptrVar, ptrtype)
3032 delete(s.vars, &ptrVar)
3033 return rptr, rlen, rcap
3036 type u2fcvtTab struct {
3037 geq, cvt2F, and, rsh, or, add ssa.Op
3038 one func(*state, ssa.Type, int64) *ssa.Value
3041 var u64_f64 u2fcvtTab = u2fcvtTab{
3043 cvt2F: ssa.OpCvt64to64F,
3045 rsh: ssa.OpRsh64Ux64,
3048 one: (*state).constInt64,
3051 var u64_f32 u2fcvtTab = u2fcvtTab{
3053 cvt2F: ssa.OpCvt64to32F,
3055 rsh: ssa.OpRsh64Ux64,
3058 one: (*state).constInt64,
3061 // Excess generality on a machine with 64-bit integer registers.
3062 // Not used on AMD64.
3063 var u32_f32 u2fcvtTab = u2fcvtTab{
3065 cvt2F: ssa.OpCvt32to32F,
3067 rsh: ssa.OpRsh32Ux32,
3070 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3071 return s.constInt32(t, int32(x))
3075 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3076 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3079 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3080 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3083 func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3085 // result = (floatY) x
3087 // y = uintX(x) ; y = x & 1
3088 // z = uintX(x) ; z = z >> 1
3091 // result = floatY(z)
3092 // result = result + result
3095 // Code borrowed from old code generator.
3096 // What's going on: large 64-bit "unsigned" looks like
3097 // negative number to hardware's integer-to-float
3098 // conversion. However, because the mantissa is only
3099 // 63 bits, we don't need the LSB, so instead we do an
3100 // unsigned right shift (divide by two), convert, and
3101 // double. However, before we do that, we need to be
3102 // sure that we do not lose a "1" if that made the
3103 // difference in the resulting rounding. Therefore, we
3104 // preserve it, and OR (not ADD) it back in. The case
3105 // that matters is when the eleven discarded bits are
3106 // equal to 10000000001; that rounds up, and the 1 cannot
3107 // be lost else it would round down if the LSB of the
3108 // candidate mantissa is 0.
3109 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3111 b.Kind = ssa.BlockIf
3113 b.Likely = ssa.BranchLikely
3115 bThen := s.f.NewBlock(ssa.BlockPlain)
3116 bElse := s.f.NewBlock(ssa.BlockPlain)
3117 bAfter := s.f.NewBlock(ssa.BlockPlain)
3121 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3124 bThen.AddEdgeTo(bAfter)
3128 one := cvttab.one(s, ft, 1)
3129 y := s.newValue2(cvttab.and, ft, x, one)
3130 z := s.newValue2(cvttab.rsh, ft, x, one)
3131 z = s.newValue2(cvttab.or, ft, z, y)
3132 a := s.newValue1(cvttab.cvt2F, tt, z)
3133 a1 := s.newValue2(cvttab.add, tt, a, a)
3136 bElse.AddEdgeTo(bAfter)
3138 s.startBlock(bAfter)
3139 return s.variable(n, n.Type)
3142 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3143 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3144 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3145 s.Fatalf("node must be a map or a channel")
3151 // return *((*int)n)
3153 // return *(((*int)n)+1)
3156 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
3157 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
3159 b.Kind = ssa.BlockIf
3161 b.Likely = ssa.BranchUnlikely
3163 bThen := s.f.NewBlock(ssa.BlockPlain)
3164 bElse := s.f.NewBlock(ssa.BlockPlain)
3165 bAfter := s.f.NewBlock(ssa.BlockPlain)
3167 // length/capacity of a nil map/chan is zero
3170 s.vars[n] = s.zeroVal(lenType)
3172 bThen.AddEdgeTo(bAfter)
3177 // length is stored in the first word for map/chan
3178 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3179 } else if n.Op == OCAP {
3180 // capacity is stored in the second word for chan
3181 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3182 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3184 s.Fatalf("op must be OLEN or OCAP")
3187 bElse.AddEdgeTo(bAfter)
3189 s.startBlock(bAfter)
3190 return s.variable(n, lenType)
3193 type f2uCvtTab struct {
3194 ltf, cvt2U, subf ssa.Op
3195 value func(*state, ssa.Type, float64) *ssa.Value
3198 var f32_u64 f2uCvtTab = f2uCvtTab{
3200 cvt2U: ssa.OpCvt32Fto64,
3202 value: (*state).constFloat32,
3205 var f64_u64 f2uCvtTab = f2uCvtTab{
3207 cvt2U: ssa.OpCvt64Fto64,
3209 value: (*state).constFloat64,
3212 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3213 return s.floatToUint(&f32_u64, n, x, ft, tt)
3215 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3216 return s.floatToUint(&f64_u64, n, x, ft, tt)
3219 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3220 // if x < 9223372036854775808.0 {
3221 // result = uintY(x)
3223 // y = x - 9223372036854775808.0
3225 // result = z | -9223372036854775808
3227 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3228 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3230 b.Kind = ssa.BlockIf
3232 b.Likely = ssa.BranchLikely
3234 bThen := s.f.NewBlock(ssa.BlockPlain)
3235 bElse := s.f.NewBlock(ssa.BlockPlain)
3236 bAfter := s.f.NewBlock(ssa.BlockPlain)
3240 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3243 bThen.AddEdgeTo(bAfter)
3247 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3248 y = s.newValue1(cvttab.cvt2U, tt, y)
3249 z := s.constInt64(tt, -9223372036854775808)
3250 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3253 bElse.AddEdgeTo(bAfter)
3255 s.startBlock(bAfter)
3256 return s.variable(n, n.Type)
3259 // ifaceType returns the value for the word containing the type.
3260 // n is the node for the interface expression.
3261 // v is the corresponding value.
3262 func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3263 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3265 if isnilinter(n.Type) {
3266 // Have *eface. The type is the first word in the struct.
3267 return s.newValue1(ssa.OpITab, byteptr, v)
3271 // The first word in the struct is the *itab.
3272 // If the *itab is nil, return 0.
3273 // Otherwise, the second word in the *itab is the type.
3275 tab := s.newValue1(ssa.OpITab, byteptr, v)
3276 s.vars[&typVar] = tab
3277 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3279 b.Kind = ssa.BlockIf
3280 b.Control = isnonnil
3281 b.Likely = ssa.BranchLikely
3283 bLoad := s.f.NewBlock(ssa.BlockPlain)
3284 bEnd := s.f.NewBlock(ssa.BlockPlain)
3288 bLoad.AddEdgeTo(bEnd)
3291 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3292 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3296 typ := s.variable(&typVar, byteptr)
3297 delete(s.vars, &typVar)
3301 // dottype generates SSA for a type assertion node.
3302 // commaok indicates whether to panic or return a bool.
3303 // If commaok is false, resok will be nil.
3304 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3305 iface := s.expr(n.Left)
3306 typ := s.ifaceType(n.Left, iface) // actual concrete type
3307 target := s.expr(typename(n.Type)) // target type
3308 if !isdirectiface(n.Type) {
3309 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3310 Fatalf("dottype needs a direct iface type %s", n.Type)
3313 if Debug_typeassert > 0 {
3314 Warnl(int(n.Lineno), "type assertion inlined")
3317 // TODO: If we have a nonempty interface and its itab field is nil,
3318 // then this test is redundant and ifaceType should just branch directly to bFail.
3319 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3321 b.Kind = ssa.BlockIf
3323 b.Likely = ssa.BranchLikely
3325 byteptr := Ptrto(Types[TUINT8])
3327 bOk := s.f.NewBlock(ssa.BlockPlain)
3328 bFail := s.f.NewBlock(ssa.BlockPlain)
3333 // on failure, panic by calling panicdottype
3335 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
3336 s.rtcall(panicdottype, false, nil, typ, target, taddr)
3338 // on success, return idata field
3340 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3343 // commaok is the more complicated case because we have
3344 // a control flow merge point.
3345 bEnd := s.f.NewBlock(ssa.BlockPlain)
3347 // type assertion succeeded
3349 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3350 s.vars[&okVar] = s.constBool(true)
3354 // type assertion failed
3356 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3357 s.vars[&okVar] = s.constBool(false)
3359 bFail.AddEdgeTo(bEnd)
3363 res = s.variable(&idataVar, byteptr)
3364 resok = s.variable(&okVar, Types[TBOOL])
3365 delete(s.vars, &idataVar)
3366 delete(s.vars, &okVar)
3370 // checkgoto checks that a goto from from to to does not
3371 // jump into a block or jump over variable declarations.
3372 // It is a copy of checkgoto in the pre-SSA backend,
3373 // modified only for line number handling.
3374 // TODO: document how this works and why it is designed the way it is.
3375 func (s *state) checkgoto(from *Node, to *Node) {
3376 if from.Sym == to.Sym {
3381 for fs := from.Sym; fs != nil; fs = fs.Link {
3385 for fs := to.Sym; fs != nil; fs = fs.Link {
3389 for ; nf > nt; nf-- {
3393 // decide what to complain about.
3394 // prefer to complain about 'into block' over declarations,
3395 // so scan backward to find most recent block or else dcl.
3400 for ; nt > nf; nt-- {
3419 lno := int(from.Left.Lineno)
3421 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
3423 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
3428 // variable returns the value of a variable at the current location.
3429 func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
3432 v = s.newValue0A(ssa.OpFwdRef, t, name)
3433 s.fwdRefs = append(s.fwdRefs, v)
3435 s.addNamedValue(name, v)
3440 func (s *state) mem() *ssa.Value {
3441 return s.variable(&memVar, ssa.TypeMem)
3444 func (s *state) linkForwardReferences() {
3445 // Build SSA graph. Each variable on its first use in a basic block
3446 // leaves a FwdRef in that block representing the incoming value
3447 // of that variable. This function links that ref up with possible definitions,
3448 // inserting Phi values as needed. This is essentially the algorithm
3449 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3450 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3452 // - We use FwdRef nodes to postpone phi building until the CFG is
3453 // completely built. That way we can avoid the notion of "sealed"
3455 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3456 for len(s.fwdRefs) > 0 {
3457 v := s.fwdRefs[len(s.fwdRefs)-1]
3458 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3463 // resolveFwdRef modifies v to be the variable's value at the start of its block.
3464 // v must be a FwdRef op.
3465 func (s *state) resolveFwdRef(v *ssa.Value) {
3467 name := v.Aux.(*Node)
3470 // Live variable at start of function.
3476 // Not SSAable. Load it.
3477 addr := s.decladdrs[name]
3479 // TODO: closure args reach here.
3480 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
3482 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3483 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3486 v.AddArgs(addr, s.startmem)
3489 if len(b.Preds) == 0 {
3490 // This block is dead; we have no predecessors and we're not the entry block.
3491 // It doesn't matter what we use here as long as it is well-formed.
3492 v.Op = ssa.OpUnknown
3495 // Find variable value on each predecessor.
3496 var argstore [4]*ssa.Value
3497 args := argstore[:0]
3498 for _, p := range b.Preds {
3499 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
3502 // Decide if we need a phi or not. We need a phi if there
3503 // are two different args (which are both not v).
3505 for _, a := range args {
3507 continue // self-reference
3510 continue // already have this witness
3513 // two witnesses, need a phi value
3518 w = a // save witness
3521 s.Fatalf("no witness for reachable phi %s", v)
3523 // One witness. Make v a copy of w.
3528 // lookupVarOutgoing finds the variable's value at the end of block b.
3529 func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
3530 m := s.defvars[b.ID]
3531 if v, ok := m[name]; ok {
3534 // The variable is not defined by b and we haven't
3535 // looked it up yet. Generate a FwdRef for the variable and return that.
3536 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3537 s.fwdRefs = append(s.fwdRefs, v)
3539 s.addNamedValue(name, v)
3543 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3544 if n.Class == Pxxx {
3545 // Don't track our dummy nodes (&memVar etc.).
3548 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3549 // Don't track autotmp_ variables.
3552 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3553 // TODO: can't handle auto compound objects with pointers yet.
3554 // The live variable analysis barfs because we don't put VARDEF
3555 // pseudos in the right place when we spill to these nodes.
3558 if n.Class == PAUTO && n.Xoffset != 0 {
3559 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3561 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3562 values, ok := s.f.NamedValues[loc]
3564 s.f.Names = append(s.f.Names, loc)
3566 s.f.NamedValues[loc] = append(values, v)
3569 // an unresolved branch
3570 type branch struct {
3571 p *obj.Prog // branch instruction
3572 b *ssa.Block // target
3575 type genState struct {
3576 // branches remembers all the branch instructions we've seen
3577 // and where they would like to go.
3580 // bstart remembers where each block starts (indexed by block ID)
3583 // deferBranches remembers all the defer branches we've seen.
3584 deferBranches []*obj.Prog
3586 // deferTarget remembers the (last) deferreturn call site.
3587 deferTarget *obj.Prog
3590 // genssa appends entries to ptxt for each instruction in f.
3591 // gcargs and gclocals are filled in with pointer maps for the frame.
3592 func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3595 e := f.Config.Frontend().(*ssaExport)
3596 // We're about to emit a bunch of Progs.
3597 // Since the only way to get here is to explicitly request it,
3598 // just fail on unimplemented instead of trying to unwind our mess.
3599 e.mustImplement = true
3601 // Remember where each block starts.
3602 s.bstart = make([]*obj.Prog, f.NumBlocks())
3604 var valueProgs map[*obj.Prog]*ssa.Value
3605 var blockProgs map[*obj.Prog]*ssa.Block
3606 const logProgs = true
3608 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3609 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3610 f.Logf("genssa %s\n", f.Name)
3611 blockProgs[Pc] = f.Blocks[0]
3614 // Emit basic blocks
3615 for i, b := range f.Blocks {
3617 // Emit values in block
3619 for _, v := range b.Values {
3623 for ; x != Pc; x = x.Link {
3628 // Emit control flow instructions for block
3630 if i < len(f.Blocks)-1 {
3631 next = f.Blocks[i+1]
3636 for ; x != Pc; x = x.Link {
3643 for _, br := range s.branches {
3644 br.p.To.Val = s.bstart[br.b.ID]
3646 if s.deferBranches != nil && s.deferTarget == nil {
3647 // This can happen when the function has a defer but
3648 // no return (because it has an infinite loop).
3652 for _, p := range s.deferBranches {
3653 p.To.Val = s.deferTarget
3657 for p := ptxt; p != nil; p = p.Link {
3659 if v, ok := valueProgs[p]; ok {
3661 } else if b, ok := blockProgs[p]; ok {
3664 s = " " // most value and branch strings are 2-3 characters long
3666 f.Logf("%s\t%s\n", s, p)
3668 if f.Config.HTML != nil {
3669 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3670 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3671 var buf bytes.Buffer
3672 buf.WriteString("<code>")
3673 buf.WriteString("<dl class=\"ssa-gen\">")
3674 for p := ptxt; p != nil; p = p.Link {
3675 buf.WriteString("<dt class=\"ssa-prog-src\">")
3676 if v, ok := valueProgs[p]; ok {
3677 buf.WriteString(v.HTML())
3678 } else if b, ok := blockProgs[p]; ok {
3679 buf.WriteString(b.HTML())
3681 buf.WriteString("</dt>")
3682 buf.WriteString("<dd class=\"ssa-prog\">")
3683 buf.WriteString(html.EscapeString(p.String()))
3684 buf.WriteString("</dd>")
3685 buf.WriteString("</li>")
3687 buf.WriteString("</dl>")
3688 buf.WriteString("</code>")
3689 f.Config.HTML.WriteColumn("genssa", buf.String())
3690 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3695 if f.StaticData != nil {
3696 for _, n := range f.StaticData.([]*Node) {
3697 if !gen_as_init(n, false) {
3698 Fatalf("non-static data marked as static: %v\n\n", n, f)
3703 // Allocate stack frame
3706 // Generate gc bitmaps.
3707 liveness(Curfn, ptxt, gcargs, gclocals)
3711 // Add frame prologue. Zero ambiguously live variables.
3712 Thearch.Defframe(ptxt)
3713 if Debug['f'] != 0 {
3717 // Remove leftover instrumentation from the instruction stream.
3720 f.Config.HTML.Close()
3723 // opregreg emits instructions for
3724 // dest := dest(To) op src(From)
3725 // and also returns the created obj.Prog so it
3726 // may be further adjusted (offset, scale, etc).
3727 func opregreg(op int, dest, src int16) *obj.Prog {
3729 p.From.Type = obj.TYPE_REG
3730 p.To.Type = obj.TYPE_REG
3736 func (s *genState) genValue(v *ssa.Value) {
3739 case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL, ssa.OpAMD64ADDW:
3741 r1 := regnum(v.Args[0])
3742 r2 := regnum(v.Args[1])
3745 p := Prog(v.Op.Asm())
3746 p.From.Type = obj.TYPE_REG
3748 p.To.Type = obj.TYPE_REG
3751 p := Prog(v.Op.Asm())
3752 p.From.Type = obj.TYPE_REG
3754 p.To.Type = obj.TYPE_REG
3759 case ssa.OpAMD64ADDQ:
3761 case ssa.OpAMD64ADDL:
3763 case ssa.OpAMD64ADDW:
3767 p.From.Type = obj.TYPE_MEM
3771 p.To.Type = obj.TYPE_REG
3774 // 2-address opcode arithmetic, symmetric
3775 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
3776 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
3777 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3778 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
3779 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
3780 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
3782 x := regnum(v.Args[0])
3783 y := regnum(v.Args[1])
3784 if x != r && y != r {
3785 opregreg(moveByType(v.Type), r, x)
3788 p := Prog(v.Op.Asm())
3789 p.From.Type = obj.TYPE_REG
3790 p.To.Type = obj.TYPE_REG
3797 // 2-address opcode arithmetic, not symmetric
3798 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
3800 x := regnum(v.Args[0])
3801 y := regnum(v.Args[1])
3804 // compute -(y-x) instead
3809 opregreg(moveByType(v.Type), r, x)
3811 opregreg(v.Op.Asm(), r, y)
3814 p := Prog(x86.ANEGQ) // TODO: use correct size? This is mostly a hack until regalloc does 2-address correctly
3815 p.To.Type = obj.TYPE_REG
3818 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3820 x := regnum(v.Args[0])
3821 y := regnum(v.Args[1])
3822 if y == r && x != r {
3823 // r/y := x op r/y, need to preserve x and rewrite to
3824 // r/y := r/y op x15
3825 x15 := int16(x86.REG_X15)
3826 // register move y to x15
3827 // register move x to y
3828 // rename y with x15
3829 opregreg(moveByType(v.Type), x15, y)
3830 opregreg(moveByType(v.Type), r, x)
3833 opregreg(moveByType(v.Type), r, x)
3835 opregreg(v.Op.Asm(), r, y)
3837 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
3838 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3839 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3840 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
3842 // Arg[0] is already in AX as it's the only register we allow
3843 // and AX is the only output
3844 x := regnum(v.Args[1])
3846 // CPU faults upon signed overflow, which occurs when most
3847 // negative int is divided by -1.
3849 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3850 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3851 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
3855 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
3858 // go ahead and sign extend to save doing it later
3861 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
3866 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
3871 c.From.Type = obj.TYPE_REG
3873 c.To.Type = obj.TYPE_CONST
3876 j.To.Type = obj.TYPE_BRANCH
3880 // for unsigned ints, we sign extend by setting DX = 0
3881 // signed ints were sign extended above
3882 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3883 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3884 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
3885 c := Prog(x86.AXORQ)
3886 c.From.Type = obj.TYPE_REG
3887 c.From.Reg = x86.REG_DX
3888 c.To.Type = obj.TYPE_REG
3889 c.To.Reg = x86.REG_DX
3892 p := Prog(v.Op.Asm())
3893 p.From.Type = obj.TYPE_REG
3896 // signed division, rest of the check for -1 case
3898 j2 := Prog(obj.AJMP)
3899 j2.To.Type = obj.TYPE_BRANCH
3902 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3903 v.Op == ssa.OpAMD64DIVW {
3906 n.To.Type = obj.TYPE_REG
3907 n.To.Reg = x86.REG_AX
3911 n.From.Type = obj.TYPE_REG
3912 n.From.Reg = x86.REG_DX
3913 n.To.Type = obj.TYPE_REG
3914 n.To.Reg = x86.REG_DX
3921 case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3922 ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
3923 // the frontend rewrites constant division by 8/16/32 bit integers into
3924 // HMUL by a constant
3925 // SSA rewrites generate the 64 bit versions
3927 // Arg[0] is already in AX as it's the only register we allow
3928 // and DX is the only output we care about (the high bits)
3929 p := Prog(v.Op.Asm())
3930 p.From.Type = obj.TYPE_REG
3931 p.From.Reg = regnum(v.Args[1])
3933 // IMULB puts the high portion in AH instead of DL,
3934 // so move it to DL for consistency
3935 if v.Type.Size() == 1 {
3936 m := Prog(x86.AMOVB)
3937 m.From.Type = obj.TYPE_REG
3938 m.From.Reg = x86.REG_AH
3939 m.To.Type = obj.TYPE_REG
3940 m.To.Reg = x86.REG_DX
3943 case ssa.OpAMD64AVGQU:
3944 // compute (x+y)/2 unsigned.
3945 // Do a 64-bit add, the overflow goes into the carry.
3946 // Shift right once and pull the carry back into the 63rd bit.
3948 x := regnum(v.Args[0])
3949 y := regnum(v.Args[1])
3950 if x != r && y != r {
3951 opregreg(moveByType(v.Type), r, x)
3954 p := Prog(x86.AADDQ)
3955 p.From.Type = obj.TYPE_REG
3956 p.To.Type = obj.TYPE_REG
3964 p.From.Type = obj.TYPE_CONST
3966 p.To.Type = obj.TYPE_REG
3969 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
3970 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
3971 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
3972 x := regnum(v.Args[0])
3975 if r == x86.REG_CX {
3976 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
3978 p := Prog(moveByType(v.Type))
3979 p.From.Type = obj.TYPE_REG
3981 p.To.Type = obj.TYPE_REG
3984 p := Prog(v.Op.Asm())
3985 p.From.Type = obj.TYPE_REG
3986 p.From.Reg = regnum(v.Args[1]) // should be CX
3987 p.To.Type = obj.TYPE_REG
3989 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
3991 a := regnum(v.Args[0])
3996 // Software optimization manual recommends add $1,reg.
3997 // But inc/dec is 1 byte smaller. ICC always uses inc
3998 // Clang/GCC choose depending on flags, but prefer add.
3999 // Experiments show that inc/dec is both a little faster
4000 // and make a binary a little smaller.
4001 case ssa.OpAMD64ADDQconst:
4003 case ssa.OpAMD64ADDLconst:
4005 case ssa.OpAMD64ADDWconst:
4009 p.To.Type = obj.TYPE_REG
4012 } else if v.AuxInt == -1 {
4015 case ssa.OpAMD64ADDQconst:
4017 case ssa.OpAMD64ADDLconst:
4019 case ssa.OpAMD64ADDWconst:
4023 p.To.Type = obj.TYPE_REG
4027 p := Prog(v.Op.Asm())
4028 p.From.Type = obj.TYPE_CONST
4029 p.From.Offset = v.AuxInt
4030 p.To.Type = obj.TYPE_REG
4037 case ssa.OpAMD64ADDQconst:
4039 case ssa.OpAMD64ADDLconst:
4041 case ssa.OpAMD64ADDWconst:
4045 p.From.Type = obj.TYPE_MEM
4047 p.From.Offset = v.AuxInt
4048 p.To.Type = obj.TYPE_REG
4050 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
4052 x := regnum(v.Args[0])
4054 p := Prog(moveByType(v.Type))
4055 p.From.Type = obj.TYPE_REG
4057 p.To.Type = obj.TYPE_REG
4060 p := Prog(v.Op.Asm())
4061 p.From.Type = obj.TYPE_CONST
4062 p.From.Offset = v.AuxInt
4063 p.To.Type = obj.TYPE_REG
4065 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
4066 // instead of using the MOVQ above.
4067 //p.From3 = new(obj.Addr)
4068 //p.From3.Type = obj.TYPE_REG
4069 //p.From3.Reg = regnum(v.Args[0])
4070 case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst:
4071 x := regnum(v.Args[0])
4073 // We have 3-op add (lea), so transforming a = b - const into
4074 // a = b + (- const), saves us 1 instruction. We can't fit
4075 // - (-1 << 31) into 4 bytes offset in lea.
4076 // We handle 2-address just fine below.
4077 if v.AuxInt == -1<<31 || x == r {
4079 // This code compensates for the fact that the register allocator
4080 // doesn't understand 2-address instructions yet. TODO: fix that.
4081 p := Prog(moveByType(v.Type))
4082 p.From.Type = obj.TYPE_REG
4084 p.To.Type = obj.TYPE_REG
4087 p := Prog(v.Op.Asm())
4088 p.From.Type = obj.TYPE_CONST
4089 p.From.Offset = v.AuxInt
4090 p.To.Type = obj.TYPE_REG
4092 } else if x == r && v.AuxInt == -1 {
4094 // x = x - (-1) is the same as x++
4095 // See OpAMD64ADDQconst comments about inc vs add $1,reg
4097 case ssa.OpAMD64SUBQconst:
4099 case ssa.OpAMD64SUBLconst:
4101 case ssa.OpAMD64SUBWconst:
4105 p.To.Type = obj.TYPE_REG
4107 } else if x == r && v.AuxInt == 1 {
4110 case ssa.OpAMD64SUBQconst:
4112 case ssa.OpAMD64SUBLconst:
4114 case ssa.OpAMD64SUBWconst:
4118 p.To.Type = obj.TYPE_REG
4123 case ssa.OpAMD64SUBQconst:
4125 case ssa.OpAMD64SUBLconst:
4127 case ssa.OpAMD64SUBWconst:
4131 p.From.Type = obj.TYPE_MEM
4133 p.From.Offset = -v.AuxInt
4134 p.To.Type = obj.TYPE_REG
4138 case ssa.OpAMD64ADDBconst,
4139 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
4140 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
4141 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
4142 ssa.OpAMD64SUBBconst, ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst,
4143 ssa.OpAMD64SHLBconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst,
4144 ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst,
4145 ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst,
4146 ssa.OpAMD64ROLBconst:
4147 // This code compensates for the fact that the register allocator
4148 // doesn't understand 2-address instructions yet. TODO: fix that.
4149 x := regnum(v.Args[0])
4152 p := Prog(moveByType(v.Type))
4153 p.From.Type = obj.TYPE_REG
4155 p.To.Type = obj.TYPE_REG
4158 p := Prog(v.Op.Asm())
4159 p.From.Type = obj.TYPE_CONST
4160 p.From.Offset = v.AuxInt
4161 p.To.Type = obj.TYPE_REG
4163 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
4165 p := Prog(v.Op.Asm())
4166 p.From.Type = obj.TYPE_REG
4168 p.To.Type = obj.TYPE_REG
4170 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
4171 p := Prog(x86.ALEAQ)
4172 p.From.Type = obj.TYPE_MEM
4173 p.From.Reg = regnum(v.Args[0])
4175 case ssa.OpAMD64LEAQ1:
4177 case ssa.OpAMD64LEAQ2:
4179 case ssa.OpAMD64LEAQ4:
4181 case ssa.OpAMD64LEAQ8:
4184 p.From.Index = regnum(v.Args[1])
4186 p.To.Type = obj.TYPE_REG
4187 p.To.Reg = regnum(v)
4188 case ssa.OpAMD64LEAQ:
4189 p := Prog(x86.ALEAQ)
4190 p.From.Type = obj.TYPE_MEM
4191 p.From.Reg = regnum(v.Args[0])
4193 p.To.Type = obj.TYPE_REG
4194 p.To.Reg = regnum(v)
4195 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
4196 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
4197 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
4198 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
4199 // Go assembler has swapped operands for UCOMISx relative to CMP,
4200 // must account for that right here.
4201 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
4202 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
4203 p := Prog(v.Op.Asm())
4204 p.From.Type = obj.TYPE_REG
4205 p.From.Reg = regnum(v.Args[0])
4206 p.To.Type = obj.TYPE_CONST
4207 p.To.Offset = v.AuxInt
4208 case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
4209 p := Prog(v.Op.Asm())
4210 p.From.Type = obj.TYPE_CONST
4211 p.From.Offset = v.AuxInt
4212 p.To.Type = obj.TYPE_REG
4213 p.To.Reg = regnum(v.Args[0])
4214 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
4216 p := Prog(v.Op.Asm())
4217 p.From.Type = obj.TYPE_CONST
4220 case ssa.OpAMD64MOVBconst:
4221 i = int64(v.AuxInt8())
4222 case ssa.OpAMD64MOVWconst:
4223 i = int64(v.AuxInt16())
4224 case ssa.OpAMD64MOVLconst:
4225 i = int64(v.AuxInt32())
4226 case ssa.OpAMD64MOVQconst:
4230 p.To.Type = obj.TYPE_REG
4232 // If flags are live at this instruction, suppress the
4233 // MOV $0,AX -> XOR AX,AX optimization.
4235 p.Mark |= x86.PRESERVEFLAGS
4237 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
4239 p := Prog(v.Op.Asm())
4240 p.From.Type = obj.TYPE_FCONST
4241 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
4242 p.To.Type = obj.TYPE_REG
4244 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload, ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload, ssa.OpAMD64MOVOload:
4245 p := Prog(v.Op.Asm())
4246 p.From.Type = obj.TYPE_MEM
4247 p.From.Reg = regnum(v.Args[0])
4249 p.To.Type = obj.TYPE_REG
4250 p.To.Reg = regnum(v)
4251 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
4252 p := Prog(v.Op.Asm())
4253 p.From.Type = obj.TYPE_MEM
4254 p.From.Reg = regnum(v.Args[0])
4257 p.From.Index = regnum(v.Args[1])
4258 p.To.Type = obj.TYPE_REG
4259 p.To.Reg = regnum(v)
4260 case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
4261 p := Prog(v.Op.Asm())
4262 p.From.Type = obj.TYPE_MEM
4263 p.From.Reg = regnum(v.Args[0])
4266 p.From.Index = regnum(v.Args[1])
4267 p.To.Type = obj.TYPE_REG
4268 p.To.Reg = regnum(v)
4269 case ssa.OpAMD64MOVWloadidx2:
4270 p := Prog(v.Op.Asm())
4271 p.From.Type = obj.TYPE_MEM
4272 p.From.Reg = regnum(v.Args[0])
4275 p.From.Index = regnum(v.Args[1])
4276 p.To.Type = obj.TYPE_REG
4277 p.To.Reg = regnum(v)
4278 case ssa.OpAMD64MOVBloadidx1:
4279 p := Prog(v.Op.Asm())
4280 p.From.Type = obj.TYPE_MEM
4281 p.From.Reg = regnum(v.Args[0])
4284 p.From.Index = regnum(v.Args[1])
4285 p.To.Type = obj.TYPE_REG
4286 p.To.Reg = regnum(v)
4287 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
4288 p := Prog(v.Op.Asm())
4289 p.From.Type = obj.TYPE_REG
4290 p.From.Reg = regnum(v.Args[1])
4291 p.To.Type = obj.TYPE_MEM
4292 p.To.Reg = regnum(v.Args[0])
4294 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
4295 p := Prog(v.Op.Asm())
4296 p.From.Type = obj.TYPE_REG
4297 p.From.Reg = regnum(v.Args[2])
4298 p.To.Type = obj.TYPE_MEM
4299 p.To.Reg = regnum(v.Args[0])
4301 p.To.Index = regnum(v.Args[1])
4303 case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
4304 p := Prog(v.Op.Asm())
4305 p.From.Type = obj.TYPE_REG
4306 p.From.Reg = regnum(v.Args[2])
4307 p.To.Type = obj.TYPE_MEM
4308 p.To.Reg = regnum(v.Args[0])
4310 p.To.Index = regnum(v.Args[1])
4312 case ssa.OpAMD64MOVWstoreidx2:
4313 p := Prog(v.Op.Asm())
4314 p.From.Type = obj.TYPE_REG
4315 p.From.Reg = regnum(v.Args[2])
4316 p.To.Type = obj.TYPE_MEM
4317 p.To.Reg = regnum(v.Args[0])
4319 p.To.Index = regnum(v.Args[1])
4321 case ssa.OpAMD64MOVBstoreidx1:
4322 p := Prog(v.Op.Asm())
4323 p.From.Type = obj.TYPE_REG
4324 p.From.Reg = regnum(v.Args[2])
4325 p.To.Type = obj.TYPE_MEM
4326 p.To.Reg = regnum(v.Args[0])
4328 p.To.Index = regnum(v.Args[1])
4330 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4331 p := Prog(v.Op.Asm())
4332 p.From.Type = obj.TYPE_CONST
4333 sc := v.AuxValAndOff()
4336 case ssa.OpAMD64MOVBstoreconst:
4338 case ssa.OpAMD64MOVWstoreconst:
4340 case ssa.OpAMD64MOVLstoreconst:
4342 case ssa.OpAMD64MOVQstoreconst:
4345 p.To.Type = obj.TYPE_MEM
4346 p.To.Reg = regnum(v.Args[0])
4347 addAux2(&p.To, v, sc.Off())
4348 case ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1:
4349 p := Prog(v.Op.Asm())
4350 p.From.Type = obj.TYPE_CONST
4351 sc := v.AuxValAndOff()
4353 case ssa.OpAMD64MOVBstoreconstidx1:
4354 p.From.Offset = int64(int8(sc.Val()))
4356 case ssa.OpAMD64MOVWstoreconstidx2:
4357 p.From.Offset = int64(int16(sc.Val()))
4359 case ssa.OpAMD64MOVLstoreconstidx4:
4360 p.From.Offset = int64(int32(sc.Val()))
4362 case ssa.OpAMD64MOVQstoreconstidx8:
4363 p.From.Offset = sc.Val()
4366 p.To.Type = obj.TYPE_MEM
4367 p.To.Reg = regnum(v.Args[0])
4368 p.To.Index = regnum(v.Args[1])
4369 addAux2(&p.To, v, sc.Off())
4370 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
4371 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
4372 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
4373 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
4374 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
4375 case ssa.OpAMD64DUFFZERO:
4376 p := Prog(obj.ADUFFZERO)
4377 p.To.Type = obj.TYPE_ADDR
4378 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
4379 p.To.Offset = v.AuxInt
4380 case ssa.OpAMD64MOVOconst:
4382 v.Unimplementedf("MOVOconst can only do constant=0")
4385 opregreg(x86.AXORPS, r, r)
4386 case ssa.OpAMD64DUFFCOPY:
4387 p := Prog(obj.ADUFFCOPY)
4388 p.To.Type = obj.TYPE_ADDR
4389 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
4390 p.To.Offset = v.AuxInt
4392 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
4393 if v.Type.IsMemory() {
4396 x := regnum(v.Args[0])
4399 opregreg(moveByType(v.Type), y, x)
4402 if v.Type.IsFlags() {
4403 v.Unimplementedf("load flags not implemented: %v", v.LongString())
4406 p := Prog(loadByType(v.Type))
4407 n, off := autoVar(v.Args[0])
4408 p.From.Type = obj.TYPE_MEM
4410 p.From.Sym = Linksym(n.Sym)
4412 if n.Class == PPARAM {
4413 p.From.Name = obj.NAME_PARAM
4414 p.From.Offset += n.Xoffset
4416 p.From.Name = obj.NAME_AUTO
4418 p.To.Type = obj.TYPE_REG
4419 p.To.Reg = regnum(v)
4421 case ssa.OpStoreReg:
4422 if v.Type.IsFlags() {
4423 v.Unimplementedf("store flags not implemented: %v", v.LongString())
4426 p := Prog(storeByType(v.Type))
4427 p.From.Type = obj.TYPE_REG
4428 p.From.Reg = regnum(v.Args[0])
4429 n, off := autoVar(v)
4430 p.To.Type = obj.TYPE_MEM
4432 p.To.Sym = Linksym(n.Sym)
4434 if n.Class == PPARAM {
4435 p.To.Name = obj.NAME_PARAM
4436 p.To.Offset += n.Xoffset
4438 p.To.Name = obj.NAME_AUTO
4441 // just check to make sure regalloc and stackalloc did it right
4442 if v.Type.IsMemory() {
4446 loc := f.RegAlloc[v.ID]
4447 for _, a := range v.Args {
4448 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
4449 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)
4453 // memory arg needs no code
4455 // input args need no code
4456 case ssa.OpAMD64LoweredGetClosurePtr:
4457 // Output is hardwired to DX only,
4458 // and DX contains the closure pointer on
4459 // closure entry, and this "instruction"
4460 // is scheduled to the very beginning
4461 // of the entry block.
4462 case ssa.OpAMD64LoweredGetG:
4464 // See the comments in cmd/internal/obj/x86/obj6.go
4465 // near CanUse1InsnTLS for a detailed explanation of these instructions.
4466 if x86.CanUse1InsnTLS(Ctxt) {
4468 p := Prog(x86.AMOVQ)
4469 p.From.Type = obj.TYPE_MEM
4470 p.From.Reg = x86.REG_TLS
4471 p.To.Type = obj.TYPE_REG
4475 // MOVQ (r)(TLS*1), r
4476 p := Prog(x86.AMOVQ)
4477 p.From.Type = obj.TYPE_REG
4478 p.From.Reg = x86.REG_TLS
4479 p.To.Type = obj.TYPE_REG
4481 q := Prog(x86.AMOVQ)
4482 q.From.Type = obj.TYPE_MEM
4484 q.From.Index = x86.REG_TLS
4486 q.To.Type = obj.TYPE_REG
4489 case ssa.OpAMD64CALLstatic:
4490 p := Prog(obj.ACALL)
4491 p.To.Type = obj.TYPE_MEM
4492 p.To.Name = obj.NAME_EXTERN
4493 p.To.Sym = Linksym(v.Aux.(*Sym))
4494 if Maxarg < v.AuxInt {
4497 case ssa.OpAMD64CALLclosure:
4498 p := Prog(obj.ACALL)
4499 p.To.Type = obj.TYPE_REG
4500 p.To.Reg = regnum(v.Args[0])
4501 if Maxarg < v.AuxInt {
4504 case ssa.OpAMD64CALLdefer:
4505 p := Prog(obj.ACALL)
4506 p.To.Type = obj.TYPE_MEM
4507 p.To.Name = obj.NAME_EXTERN
4508 p.To.Sym = Linksym(Deferproc.Sym)
4509 if Maxarg < v.AuxInt {
4512 // defer returns in rax:
4513 // 0 if we should continue executing
4514 // 1 if we should jump to deferreturn call
4515 p = Prog(x86.ATESTL)
4516 p.From.Type = obj.TYPE_REG
4517 p.From.Reg = x86.REG_AX
4518 p.To.Type = obj.TYPE_REG
4519 p.To.Reg = x86.REG_AX
4521 p.To.Type = obj.TYPE_BRANCH
4522 s.deferBranches = append(s.deferBranches, p)
4523 case ssa.OpAMD64CALLgo:
4524 p := Prog(obj.ACALL)
4525 p.To.Type = obj.TYPE_MEM
4526 p.To.Name = obj.NAME_EXTERN
4527 p.To.Sym = Linksym(Newproc.Sym)
4528 if Maxarg < v.AuxInt {
4531 case ssa.OpAMD64CALLinter:
4532 p := Prog(obj.ACALL)
4533 p.To.Type = obj.TYPE_REG
4534 p.To.Reg = regnum(v.Args[0])
4535 if Maxarg < v.AuxInt {
4538 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4539 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
4540 x := regnum(v.Args[0])
4543 p := Prog(moveByType(v.Type))
4544 p.From.Type = obj.TYPE_REG
4546 p.To.Type = obj.TYPE_REG
4549 p := Prog(v.Op.Asm())
4550 p.To.Type = obj.TYPE_REG
4552 case ssa.OpAMD64SQRTSD:
4553 p := Prog(v.Op.Asm())
4554 p.From.Type = obj.TYPE_REG
4555 p.From.Reg = regnum(v.Args[0])
4556 p.To.Type = obj.TYPE_REG
4557 p.To.Reg = regnum(v)
4558 case ssa.OpSP, ssa.OpSB:
4560 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4561 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4562 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
4563 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
4564 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
4565 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
4566 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
4567 p := Prog(v.Op.Asm())
4568 p.To.Type = obj.TYPE_REG
4569 p.To.Reg = regnum(v)
4571 case ssa.OpAMD64SETNEF:
4572 p := Prog(v.Op.Asm())
4573 p.To.Type = obj.TYPE_REG
4574 p.To.Reg = regnum(v)
4575 q := Prog(x86.ASETPS)
4576 q.To.Type = obj.TYPE_REG
4577 q.To.Reg = x86.REG_AX
4578 // TODO AORQ copied from old code generator, why not AORB?
4579 opregreg(x86.AORQ, regnum(v), x86.REG_AX)
4581 case ssa.OpAMD64SETEQF:
4582 p := Prog(v.Op.Asm())
4583 p.To.Type = obj.TYPE_REG
4584 p.To.Reg = regnum(v)
4585 q := Prog(x86.ASETPC)
4586 q.To.Type = obj.TYPE_REG
4587 q.To.Reg = x86.REG_AX
4588 // TODO AANDQ copied from old code generator, why not AANDB?
4589 opregreg(x86.AANDQ, regnum(v), x86.REG_AX)
4591 case ssa.OpAMD64InvertFlags:
4592 v.Fatalf("InvertFlags should never make it to codegen %v", v)
4593 case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
4594 v.Fatalf("Flag* ops should never make it to codegen %v", v)
4595 case ssa.OpAMD64REPSTOSQ:
4598 case ssa.OpAMD64REPMOVSQ:
4602 Gvardef(v.Aux.(*Node))
4604 gvarkill(v.Aux.(*Node))
4606 gvarlive(v.Aux.(*Node))
4607 case ssa.OpAMD64LoweredNilCheck:
4608 // Optimization - if the subsequent block has a load or store
4609 // at the same address, we don't need to issue this instruction.
4611 for _, w := range v.Block.Succs[0].Values {
4612 if w.Op == ssa.OpPhi {
4613 if w.Type.IsMemory() {
4618 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4619 // w doesn't use a store - can't be a memory op.
4622 if w.Args[len(w.Args)-1] != mem {
4623 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4626 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
4627 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
4628 ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload,
4629 ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload:
4630 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
4631 if Debug_checknil != 0 && int(v.Line) > 1 {
4632 Warnl(int(v.Line), "removed nil check")
4636 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4637 off := ssa.ValAndOff(v.AuxInt).Off()
4638 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
4639 if Debug_checknil != 0 && int(v.Line) > 1 {
4640 Warnl(int(v.Line), "removed nil check")
4645 if w.Type.IsMemory() {
4646 // We can't delay the nil check past the next store.
4650 // Issue a load which will fault if the input is nil.
4651 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4652 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4653 // but it doesn't have false dependency on AX.
4654 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4655 // That trades clobbering flags for clobbering a register.
4656 p := Prog(x86.ATESTB)
4657 p.From.Type = obj.TYPE_REG
4658 p.From.Reg = x86.REG_AX
4659 p.To.Type = obj.TYPE_MEM
4660 p.To.Reg = regnum(v.Args[0])
4662 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
4663 Warnl(int(v.Line), "generated nil check")
4666 v.Unimplementedf("genValue not implemented: %s", v.LongString())
4670 // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
4671 func (s *genState) markMoves(b *ssa.Block) {
4672 flive := b.FlagsLiveAtEnd
4673 if b.Control != nil && b.Control.Type.IsFlags() {
4676 for i := len(b.Values) - 1; i >= 0; i-- {
4678 if flive && (v.Op == ssa.OpAMD64MOVWconst || v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
4679 // The "mark" is any non-nil Aux value.
4682 if v.Type.IsFlags() {
4685 for _, a := range v.Args {
4686 if a.Type.IsFlags() {
4693 // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4694 func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4696 // TODO: use zero register on archs that support it.
4697 p.From.Type = obj.TYPE_CONST
4699 p.To.Type = obj.TYPE_MEM
4701 p.To.Offset = offset
4703 nleft = nbytes - width
4704 return nleft, offset
4707 var blockJump = [...]struct {
4710 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4711 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4712 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4713 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4714 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4715 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4716 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4717 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4718 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4719 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
4720 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4721 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4724 type floatingEQNEJump struct {
4728 var eqfJumps = [2][2]floatingEQNEJump{
4729 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4730 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4732 var nefJumps = [2][2]floatingEQNEJump{
4733 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4734 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4737 func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4738 p := Prog(jumps.jump)
4739 p.To.Type = obj.TYPE_BRANCH
4741 branches = append(branches, branch{p, b.Succs[to]})
4745 // liblink reorders the instruction stream as it sees fit.
4746 // Pass along what we know so liblink can make use of it.
4747 // TODO: Once we've fully switched to SSA,
4748 // make liblink leave our output alone.
4750 case ssa.BranchUnlikely:
4751 p.From.Type = obj.TYPE_CONST
4753 case ssa.BranchLikely:
4754 p.From.Type = obj.TYPE_CONST
4760 func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
4764 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4765 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
4767 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4768 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4770 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4771 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4773 q.To.Type = obj.TYPE_BRANCH
4774 s.branches = append(s.branches, branch{q, b.Succs[1]})
4778 func (s *genState) genBlock(b, next *ssa.Block) {
4782 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
4783 if b.Succs[0] != next {
4785 p.To.Type = obj.TYPE_BRANCH
4786 s.branches = append(s.branches, branch{p, b.Succs[0]})
4789 Prog(obj.AUNDEF) // tell plive.go that we never reach here
4795 case ssa.BlockRetJmp:
4797 p.To.Type = obj.TYPE_MEM
4798 p.To.Name = obj.NAME_EXTERN
4799 p.To.Sym = Linksym(b.Aux.(*Sym))
4801 case ssa.BlockAMD64EQF:
4802 genFPJump(s, b, next, &eqfJumps)
4804 case ssa.BlockAMD64NEF:
4805 genFPJump(s, b, next, &nefJumps)
4807 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4808 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4809 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4810 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4811 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
4812 jmp := blockJump[b.Kind]
4817 p = Prog(jmp.invasm)
4819 p.To.Type = obj.TYPE_BRANCH
4820 s.branches = append(s.branches, branch{p, b.Succs[1]})
4823 p.To.Type = obj.TYPE_BRANCH
4824 s.branches = append(s.branches, branch{p, b.Succs[0]})
4827 p.To.Type = obj.TYPE_BRANCH
4828 s.branches = append(s.branches, branch{p, b.Succs[0]})
4830 q.To.Type = obj.TYPE_BRANCH
4831 s.branches = append(s.branches, branch{q, b.Succs[1]})
4834 // liblink reorders the instruction stream as it sees fit.
4835 // Pass along what we know so liblink can make use of it.
4836 // TODO: Once we've fully switched to SSA,
4837 // make liblink leave our output alone.
4839 case ssa.BranchUnlikely:
4840 p.From.Type = obj.TYPE_CONST
4842 case ssa.BranchLikely:
4843 p.From.Type = obj.TYPE_CONST
4848 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
4852 func (s *genState) deferReturn() {
4853 // Deferred calls will appear to be returning to
4854 // the CALL deferreturn(SB) that we are about to emit.
4855 // However, the stack trace code will show the line
4856 // of the instruction byte before the return PC.
4857 // To avoid that being an unrelated instruction,
4858 // insert an actual hardware NOP that will have the right line number.
4859 // This is different from obj.ANOP, which is a virtual no-op
4860 // that doesn't make it into the instruction stream.
4863 p := Prog(obj.ACALL)
4864 p.To.Type = obj.TYPE_MEM
4865 p.To.Name = obj.NAME_EXTERN
4866 p.To.Sym = Linksym(Deferreturn.Sym)
4869 // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4870 func addAux(a *obj.Addr, v *ssa.Value) {
4871 addAux2(a, v, v.AuxInt)
4873 func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
4874 if a.Type != obj.TYPE_MEM {
4875 v.Fatalf("bad addAux addr %s", a)
4877 // add integer offset
4880 // If no additional symbol offset, we're done.
4884 // Add symbol's offset from its base register.
4885 switch sym := v.Aux.(type) {
4886 case *ssa.ExternSymbol:
4887 a.Name = obj.NAME_EXTERN
4888 a.Sym = Linksym(sym.Sym.(*Sym))
4889 case *ssa.ArgSymbol:
4890 n := sym.Node.(*Node)
4891 a.Name = obj.NAME_PARAM
4893 a.Sym = Linksym(n.Orig.Sym)
4894 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
4895 case *ssa.AutoSymbol:
4896 n := sym.Node.(*Node)
4897 a.Name = obj.NAME_AUTO
4899 a.Sym = Linksym(n.Sym)
4901 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4905 // extendIndex extends v to a full int width.
4906 func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4907 size := v.Type.Size()
4908 if size == s.config.IntSize {
4911 if size > s.config.IntSize {
4912 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
4913 // the high word and branch to out-of-bounds failure if it is not 0.
4914 s.Unimplementedf("64->32 index truncation not implemented")
4918 // Extend value to the required size
4920 if v.Type.IsSigned() {
4921 switch 10*size + s.config.IntSize {
4923 op = ssa.OpSignExt8to32
4925 op = ssa.OpSignExt8to64
4927 op = ssa.OpSignExt16to32
4929 op = ssa.OpSignExt16to64
4931 op = ssa.OpSignExt32to64
4933 s.Fatalf("bad signed index extension %s", v.Type)
4936 switch 10*size + s.config.IntSize {
4938 op = ssa.OpZeroExt8to32
4940 op = ssa.OpZeroExt8to64
4942 op = ssa.OpZeroExt16to32
4944 op = ssa.OpZeroExt16to64
4946 op = ssa.OpZeroExt32to64
4948 s.Fatalf("bad unsigned index extension %s", v.Type)
4951 return s.newValue1(op, Types[TINT], v)
4954 // ssaRegToReg maps ssa register numbers to obj register numbers.
4955 var ssaRegToReg = [...]int16{
4988 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
4989 // TODO: arch-dependent
4992 // loadByType returns the load instruction of the given type.
4993 func loadByType(t ssa.Type) int {
4994 // For x86, there's no difference between load and store opcodes.
4995 return storeByType(t)
4998 // storeByType returns the store instruction of the given type.
4999 func storeByType(t ssa.Type) int {
5020 panic("bad store type")
5023 // moveByType returns the reg->reg move instruction of the given type.
5024 func moveByType(t ssa.Type) int {
5026 // Moving the whole sse2 register is faster
5027 // than moving just the correct low portion of it.
5040 panic("bad int register width")
5043 panic("bad register type")
5046 // regnum returns the register (in cmd/internal/obj numbering) to
5047 // which v has been allocated. Panics if v is not assigned to a
5049 // TODO: Make this panic again once it stops happening routinely.
5050 func regnum(v *ssa.Value) int16 {
5051 reg := v.Block.Func.RegAlloc[v.ID]
5053 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
5056 return ssaRegToReg[reg.(*ssa.Register).Num]
5059 // autoVar returns a *Node and int64 representing the auto variable and offset within it
5060 // where v should be spilled.
5061 func autoVar(v *ssa.Value) (*Node, int64) {
5062 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
5063 if v.Type.Size() > loc.Type.Size() {
5064 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
5066 return loc.N.(*Node), loc.Off
5069 // fieldIdx finds the index of the field referred to by the ODOT node n.
5070 func fieldIdx(n *Node) int64 {
5073 if t.Etype != TSTRUCT {
5074 panic("ODOT's LHS is not a struct")
5078 for t1 := t.Type; t1 != nil; t1 = t1.Down {
5079 if t1.Etype != TFIELD {
5080 panic("non-TFIELD in TSTRUCT")
5082 if t1.Sym != f.Sym {
5086 if t1.Width != n.Xoffset {
5087 panic("field offset doesn't match")
5091 panic(fmt.Sprintf("can't find field in expr %s\n", n))
5093 // TODO: keep the result of this fucntion somewhere in the ODOT Node
5094 // so we don't have to recompute it each time we need it.
5097 // ssaExport exports a bunch of compiler services for the ssa backend.
5098 type ssaExport struct {
5104 func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
5105 func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
5106 func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
5107 func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
5108 func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
5109 func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
5110 func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
5111 func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
5112 func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
5113 func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
5114 func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
5115 func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
5116 func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
5117 func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
5118 func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
5120 // StringData returns a symbol (a *Sym wrapped in an interface) which
5121 // is the data component of a global string constant containing s.
5122 func (*ssaExport) StringData(s string) interface{} {
5123 // TODO: is idealstring correct? It might not matter...
5124 _, data := stringsym(s)
5125 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
5128 func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
5129 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
5130 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
5134 func (e *ssaExport) CanSSA(t ssa.Type) bool {
5135 return canSSAType(t.(*Type))
5138 func (e *ssaExport) Line(line int32) string {
5139 return Ctxt.Line(int(line))
5142 // Log logs a message from the compiler.
5143 func (e *ssaExport) Logf(msg string, args ...interface{}) {
5144 // If e was marked as unimplemented, anything could happen. Ignore.
5145 if e.log && !e.unimplemented {
5146 fmt.Printf(msg, args...)
5150 func (e *ssaExport) Log() bool {
5154 // Fatal reports a compiler error and exits.
5155 func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
5156 // If e was marked as unimplemented, anything could happen. Ignore.
5157 if !e.unimplemented {
5159 Fatalf(msg, args...)
5163 // Unimplemented reports that the function cannot be compiled.
5164 // It will be removed once SSA work is complete.
5165 func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
5166 if e.mustImplement {
5168 Fatalf(msg, args...)
5170 const alwaysLog = false // enable to calculate top unimplemented features
5171 if !e.unimplemented && (e.log || alwaysLog) {
5172 // first implementation failure, print explanation
5173 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
5175 e.unimplemented = true
5178 // Warnl reports a "warning", which is usually flag-triggered
5179 // logging output for the benefit of tests.
5180 func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
5181 Warnl(line, fmt_, args...)
5184 func (e *ssaExport) Debug_checknil() bool {
5185 return Debug_checknil != 0
5188 func (n *Node) Typ() ssa.Type {