1 // Copyright 2015 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 "cmd/compile/internal/ssa"
17 "cmd/internal/obj/x86"
20 // Smallest possible faulting page at address zero.
21 const minZeroPage = 4096
23 var ssaConfig *ssa.Config
26 func initssa() *ssa.Config {
27 ssaExp.unimplemented = false
28 ssaExp.mustImplement = true
30 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
35 func shouldssa(fn *Node) bool {
36 if Thearch.Thestring != "amd64" {
40 // Environment variable control of SSA CG
41 // 1. IF GOSSAFUNC == current function name THEN
42 // compile this function with SSA and log output to ssa.html
44 // 2. IF GOSSAHASH == "" THEN
45 // compile this function (and everything else) with SSA
47 // 3. IF GOSSAHASH == "n" or "N"
48 // IF GOSSAPKG == current package name THEN
49 // compile this function (and everything in this package) with SSA
51 // use the old back end for this function.
52 // This is for compatibility with existing test harness and should go away.
54 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
55 // compile this function with SSA
57 // compile this function with the old back end.
59 // Plan is for 3 to be removed when the tests are revised.
60 // SSA is now default, and is disabled by setting
61 // GOSSAHASH to n or N, or selectively with strings of
64 name := fn.Func.Nname.Sym.Name
66 funcname := os.Getenv("GOSSAFUNC")
68 // If GOSSAFUNC is set, compile only that function.
69 return name == funcname
72 pkg := os.Getenv("GOSSAPKG")
74 // If GOSSAPKG is set, compile only that package.
75 return localpkg.Name == pkg
78 return initssa().DebugHashMatch("GOSSAHASH", name)
81 // buildssa builds an SSA function.
82 func buildssa(fn *Node) *ssa.Func {
83 name := fn.Func.Nname.Sym.Name
84 printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
86 fmt.Println("generating SSA for", name)
87 dumpslice("buildssa-enter", fn.Func.Enter.Slice())
88 dumplist("buildssa-body", fn.Nbody)
89 dumpslice("buildssa-exit", fn.Func.Exit.Slice())
96 // TODO(khr): build config just once at the start of the compiler binary
101 s.f = s.config.NewFunc()
103 s.exitCode = fn.Func.Exit
104 s.panics = map[funcLine]*ssa.Block{}
106 if name == os.Getenv("GOSSAFUNC") {
107 // TODO: tempfile? it is handy to have the location
108 // of this file be stable, so you can just reload in the browser.
109 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
110 // TODO: generate and print a mapping from nodes to values and blocks
114 s.config.HTML.Close()
118 // Allocate starting block
119 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
121 // Allocate starting values
122 s.labels = map[string]*ssaLabel{}
123 s.labeledNodes = map[*Node]*ssaLabel{}
124 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
125 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
126 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
128 s.startBlock(s.f.Entry)
129 s.vars[&memVar] = s.startmem
131 s.varsyms = map[*Node]interface{}{}
133 // Generate addresses of local declarations
134 s.decladdrs = map[*Node]*ssa.Value{}
135 for _, n := range fn.Func.Dcl {
138 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
139 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
141 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
142 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
143 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
144 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
145 // This ends up wrong, have to do it at the PARAM node instead.
146 case PAUTO, PPARAMOUT:
147 // processed at each use, to prevent Addr coming
150 // local function - already handled by frontend
153 if n.Class&PHEAP != 0 {
156 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
160 // Convert the AST-based IR to the SSA-based IR
161 s.stmts(fn.Func.Enter)
164 // fallthrough to exit
165 if s.curBlock != nil {
169 b.Kind = ssa.BlockRet
173 // Check that we used all labels
174 for name, lab := range s.labels {
175 if !lab.used() && !lab.reported {
176 yyerrorl(int(lab.defNode.Lineno), "label %v defined and not used", name)
179 if lab.used() && !lab.defined() && !lab.reported {
180 yyerrorl(int(lab.useNode.Lineno), "label %v not defined", name)
185 // Check any forward gotos. Non-forward gotos have already been checked.
186 for _, n := range s.fwdGotos {
187 lab := s.labels[n.Left.Sym.Name]
188 // If the label is undefined, we have already have printed an error.
190 s.checkgoto(n, lab.defNode)
199 // Link up variable uses to variable definitions
200 s.linkForwardReferences()
202 // Don't carry reference this around longer than necessary
205 // Main call to ssa package to compile function
212 // configuration (arch) information
215 // function we're building
218 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
219 labels map[string]*ssaLabel
220 labeledNodes map[*Node]*ssaLabel
222 // gotos that jump forward; required for deferred checkgoto calls
224 // Code that must precede any return
225 // (e.g., copying value of heap-escaped paramout back to true paramout)
228 // unlabeled break and continue statement tracking
229 breakTo *ssa.Block // current target for plain break statement
230 continueTo *ssa.Block // current target for plain continue statement
232 // current location where we're interpreting the AST
235 // variable assignments in the current block (map from variable symbol to ssa value)
236 // *Node is the unique identifier (an ONAME Node) for the variable.
237 vars map[*Node]*ssa.Value
239 // all defined variables at the end of each block. Indexed by block ID.
240 defvars []map[*Node]*ssa.Value
242 // addresses of PPARAM and PPARAMOUT variables.
243 decladdrs map[*Node]*ssa.Value
245 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
246 varsyms map[*Node]interface{}
248 // starting values. Memory, stack pointer, and globals pointer
253 // line number stack. The current line number is top of stack
256 // list of panic calls by function name and line number.
257 // Used to deduplicate panic calls.
258 panics map[funcLine]*ssa.Block
260 // list of FwdRef values.
264 type funcLine struct {
269 type ssaLabel struct {
270 target *ssa.Block // block identified by this label
271 breakTarget *ssa.Block // block to break to in control flow node identified by this label
272 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
273 defNode *Node // label definition Node (OLABEL)
274 // Label use Node (OGOTO, OBREAK, OCONTINUE).
275 // Used only for error detection and reporting.
276 // There might be multiple uses, but we only need to track one.
278 reported bool // reported indicates whether an error has already been reported for this label
281 // defined reports whether the label has a definition (OLABEL node).
282 func (l *ssaLabel) defined() bool { return l.defNode != nil }
284 // used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
285 func (l *ssaLabel) used() bool { return l.useNode != nil }
287 // label returns the label associated with sym, creating it if necessary.
288 func (s *state) label(sym *Sym) *ssaLabel {
289 lab := s.labels[sym.Name]
292 s.labels[sym.Name] = lab
297 func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
298 func (s *state) Log() bool { return s.config.Log() }
299 func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
300 func (s *state) Unimplementedf(msg string, args ...interface{}) {
301 s.config.Unimplementedf(s.peekLine(), msg, args...)
303 func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
304 func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
307 // dummy node for the memory variable
308 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
310 // dummy nodes for temporary variables
311 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
312 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
313 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
314 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
315 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
318 // startBlock sets the current block we're generating code in to b.
319 func (s *state) startBlock(b *ssa.Block) {
320 if s.curBlock != nil {
321 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
324 s.vars = map[*Node]*ssa.Value{}
327 // endBlock marks the end of generating code for the current block.
328 // Returns the (former) current block. Returns nil if there is no current
329 // block, i.e. if no code flows to the current execution point.
330 func (s *state) endBlock() *ssa.Block {
335 for len(s.defvars) <= int(b.ID) {
336 s.defvars = append(s.defvars, nil)
338 s.defvars[b.ID] = s.vars
341 b.Line = s.peekLine()
345 // pushLine pushes a line number on the line number stack.
346 func (s *state) pushLine(line int32) {
347 s.line = append(s.line, line)
350 // popLine pops the top of the line number stack.
351 func (s *state) popLine() {
352 s.line = s.line[:len(s.line)-1]
355 // peekLine peek the top of the line number stack.
356 func (s *state) peekLine() int32 {
357 return s.line[len(s.line)-1]
360 func (s *state) Error(msg string, args ...interface{}) {
361 yyerrorl(int(s.peekLine()), msg, args...)
364 // newValue0 adds a new value with no arguments to the current block.
365 func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
366 return s.curBlock.NewValue0(s.peekLine(), op, t)
369 // newValue0A adds a new value with no arguments and an aux value to the current block.
370 func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
371 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
374 // newValue0I adds a new value with no arguments and an auxint value to the current block.
375 func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
376 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
379 // newValue1 adds a new value with one argument to the current block.
380 func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
381 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
384 // newValue1A adds a new value with one argument and an aux value to the current block.
385 func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
386 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
389 // newValue1I adds a new value with one argument and an auxint value to the current block.
390 func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
391 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
394 // newValue2 adds a new value with two arguments to the current block.
395 func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
396 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
399 // newValue2I adds a new value with two arguments and an auxint value to the current block.
400 func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
401 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
404 // newValue3 adds a new value with three arguments to the current block.
405 func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
406 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
409 // newValue3I adds a new value with three arguments and an auxint value to the current block.
410 func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
411 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
414 // entryNewValue0 adds a new value with no arguments to the entry block.
415 func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
416 return s.f.Entry.NewValue0(s.peekLine(), op, t)
419 // entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
420 func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
421 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
424 // entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
425 func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
426 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
429 // entryNewValue1 adds a new value with one argument to the entry block.
430 func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
431 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
434 // entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
435 func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
436 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
439 // entryNewValue1A adds a new value with one argument and an aux value to the entry block.
440 func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
441 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
444 // entryNewValue2 adds a new value with two arguments to the entry block.
445 func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
446 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
449 // const* routines add a new const value to the entry block.
450 func (s *state) constBool(c bool) *ssa.Value {
451 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
453 func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
454 return s.f.ConstInt8(s.peekLine(), t, c)
456 func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
457 return s.f.ConstInt16(s.peekLine(), t, c)
459 func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
460 return s.f.ConstInt32(s.peekLine(), t, c)
462 func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
463 return s.f.ConstInt64(s.peekLine(), t, c)
465 func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
466 return s.f.ConstFloat32(s.peekLine(), t, c)
468 func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
469 return s.f.ConstFloat64(s.peekLine(), t, c)
471 func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
472 if s.config.IntSize == 8 {
473 return s.constInt64(t, c)
475 if int64(int32(c)) != c {
476 s.Fatalf("integer constant too big %d", c)
478 return s.constInt32(t, int32(c))
481 func (s *state) stmts(a Nodes) {
482 for _, x := range a.Slice() {
487 // ssaStmtList converts the statement n to SSA and adds it to s.
488 func (s *state) stmtList(l *NodeList) {
489 for ; l != nil; l = l.Next {
494 // ssaStmt converts the statement n to SSA and adds it to s.
495 func (s *state) stmt(n *Node) {
499 // If s.curBlock is nil, then we're about to generate dead code.
500 // We can't just short-circuit here, though,
501 // because we check labels and gotos as part of SSA generation.
502 // Provide a block for the dead code so that we don't have
503 // to add special cases everywhere else.
504 if s.curBlock == nil {
505 dead := s.f.NewBlock(ssa.BlockPlain)
516 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
518 // Expression statements
519 case OCALLFUNC, OCALLMETH, OCALLINTER:
520 s.call(n, callNormal)
521 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
522 (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
523 n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo")) {
526 b.Kind = ssa.BlockExit
528 // TODO: never rewrite OPANIC to OCALLFUNC in the
529 // first place. Need to wait until all backends
533 s.call(n.Left, callDefer)
535 s.call(n.Left, callGo)
538 res, resok := s.dottype(n.Rlist.N, true)
539 s.assign(n.List.N, res, needwritebarrier(n.List.N, n.Rlist.N), false, n.Lineno)
540 s.assign(n.List.Next.N, resok, false, false, n.Lineno)
544 if n.Left.Class&PHEAP == 0 {
547 if compiling_runtime != 0 {
548 Fatalf("%v escapes to heap, not allowed in runtime.", n)
551 // TODO: the old pass hides the details of PHEAP
552 // variables behind ONAME nodes. Figure out if it's better
553 // to rewrite the tree and make the heapaddr construct explicit
554 // or to keep this detail hidden behind the scenes.
555 palloc := prealloc[n.Left]
557 palloc = callnew(n.Left.Type)
558 prealloc[n.Left] = palloc
561 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno)
567 // Empty identifier is valid but useless.
568 // See issues 11589, 11593.
574 // Associate label with its control flow node, if any
575 if ctl := n.Name.Defn; ctl != nil {
577 case OFOR, OSWITCH, OSELECT:
578 s.labeledNodes[ctl] = lab
585 s.Error("label %v already defined at %v", sym, Ctxt.Line(int(lab.defNode.Lineno)))
588 // The label might already have a target block via a goto.
589 if lab.target == nil {
590 lab.target = s.f.NewBlock(ssa.BlockPlain)
593 // go to that label (we pretend "label:" is preceded by "goto label")
595 b.AddEdgeTo(lab.target)
596 s.startBlock(lab.target)
602 if lab.target == nil {
603 lab.target = s.f.NewBlock(ssa.BlockPlain)
610 s.checkgoto(n, lab.defNode)
612 s.fwdGotos = append(s.fwdGotos, n)
616 b.AddEdgeTo(lab.target)
619 // Check whether we can generate static data rather than code.
620 // If so, ignore n and defer data generation until codegen.
621 // Failure to do this causes writes to readonly symbols.
622 if gen_as_init(n, true) {
624 if s.f.StaticData != nil {
625 data = s.f.StaticData.([]*Node)
627 s.f.StaticData = append(data, n)
640 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
641 // All literals with nonzero fields have already been
642 // rewritten during walk. Any that remain are just T{}
643 // or equivalents. Use the zero value.
645 Fatalf("literal with nonzero value in SSA: %v", rhs)
650 needwb := n.Op == OASWB && rhs != nil
651 deref := !canSSAType(t)
654 r = nil // Signal assign to use OpZero.
656 r = s.addr(rhs, false)
665 if rhs != nil && rhs.Op == OAPPEND {
666 // Yuck! The frontend gets rid of the write barrier, but we need it!
667 // At least, we need it in the case where growslice is called.
668 // TODO: Do the write barrier on just the growslice branch.
669 // TODO: just add a ptr graying to the end of growslice?
670 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
671 // They get similar wb-removal treatment in walk.go:OAS.
675 s.assign(n.Left, r, needwb, deref, n.Lineno)
678 bThen := s.f.NewBlock(ssa.BlockPlain)
679 bEnd := s.f.NewBlock(ssa.BlockPlain)
682 bElse = s.f.NewBlock(ssa.BlockPlain)
683 s.condBranch(n.Left, bThen, bElse, n.Likely)
685 s.condBranch(n.Left, bThen, bEnd, n.Likely)
690 if b := s.endBlock(); b != nil {
697 if b := s.endBlock(); b != nil {
708 b.Kind = ssa.BlockRet
715 b.Kind = ssa.BlockRetJmp
719 case OCONTINUE, OBREAK:
731 // plain break/continue
733 s.Error("%s is not in a loop", op)
736 // nothing to do; "to" is already the correct target
738 // labeled break/continue; look up the target
745 s.Error("%s label not defined: %v", op, sym)
751 to = lab.continueTarget
756 // Valid label but not usable with a break/continue here, e.g.:
762 s.Error("invalid %s label %v", op, sym)
772 // OFOR: for Ninit; Left; Right { Nbody }
773 bCond := s.f.NewBlock(ssa.BlockPlain)
774 bBody := s.f.NewBlock(ssa.BlockPlain)
775 bIncr := s.f.NewBlock(ssa.BlockPlain)
776 bEnd := s.f.NewBlock(ssa.BlockPlain)
778 // first, jump to condition test
782 // generate code to test condition
785 s.condBranch(n.Left, bBody, bEnd, 1)
788 b.Kind = ssa.BlockPlain
792 // set up for continue/break in body
793 prevContinue := s.continueTo
794 prevBreak := s.breakTo
797 lab := s.labeledNodes[n]
800 lab.continueTarget = bIncr
801 lab.breakTarget = bEnd
808 // tear down continue/break
809 s.continueTo = prevContinue
810 s.breakTo = prevBreak
812 lab.continueTarget = nil
813 lab.breakTarget = nil
816 // done with body, goto incr
817 if b := s.endBlock(); b != nil {
826 if b := s.endBlock(); b != nil {
831 case OSWITCH, OSELECT:
832 // These have been mostly rewritten by the front end into their Nbody fields.
833 // Our main task is to correctly hook up any break statements.
834 bEnd := s.f.NewBlock(ssa.BlockPlain)
836 prevBreak := s.breakTo
838 lab := s.labeledNodes[n]
841 lab.breakTarget = bEnd
844 // generate body code
847 s.breakTo = prevBreak
849 lab.breakTarget = nil
852 // OSWITCH never falls through (s.curBlock == nil here).
853 // OSELECT does not fall through if we're calling selectgo.
854 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
855 // In those latter cases, go to the code after the select.
856 if b := s.endBlock(); b != nil {
862 // Insert a varkill op to record that a variable is no longer live.
863 // We only care about liveness info at call sites, so putting the
864 // varkill in the store chain is enough to keep it correctly ordered
865 // with respect to call ops.
867 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
871 // Insert a varlive op to record that a variable is still live.
872 if !n.Left.Addrtaken {
873 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
875 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
882 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
886 type opAndType struct {
891 var opToSSA = map[opAndType]ssa.Op{
892 opAndType{OADD, TINT8}: ssa.OpAdd8,
893 opAndType{OADD, TUINT8}: ssa.OpAdd8,
894 opAndType{OADD, TINT16}: ssa.OpAdd16,
895 opAndType{OADD, TUINT16}: ssa.OpAdd16,
896 opAndType{OADD, TINT32}: ssa.OpAdd32,
897 opAndType{OADD, TUINT32}: ssa.OpAdd32,
898 opAndType{OADD, TPTR32}: ssa.OpAdd32,
899 opAndType{OADD, TINT64}: ssa.OpAdd64,
900 opAndType{OADD, TUINT64}: ssa.OpAdd64,
901 opAndType{OADD, TPTR64}: ssa.OpAdd64,
902 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
903 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
905 opAndType{OSUB, TINT8}: ssa.OpSub8,
906 opAndType{OSUB, TUINT8}: ssa.OpSub8,
907 opAndType{OSUB, TINT16}: ssa.OpSub16,
908 opAndType{OSUB, TUINT16}: ssa.OpSub16,
909 opAndType{OSUB, TINT32}: ssa.OpSub32,
910 opAndType{OSUB, TUINT32}: ssa.OpSub32,
911 opAndType{OSUB, TINT64}: ssa.OpSub64,
912 opAndType{OSUB, TUINT64}: ssa.OpSub64,
913 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
914 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
916 opAndType{ONOT, TBOOL}: ssa.OpNot,
918 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
919 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
920 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
921 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
922 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
923 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
924 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
925 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
926 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
927 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
929 opAndType{OCOM, TINT8}: ssa.OpCom8,
930 opAndType{OCOM, TUINT8}: ssa.OpCom8,
931 opAndType{OCOM, TINT16}: ssa.OpCom16,
932 opAndType{OCOM, TUINT16}: ssa.OpCom16,
933 opAndType{OCOM, TINT32}: ssa.OpCom32,
934 opAndType{OCOM, TUINT32}: ssa.OpCom32,
935 opAndType{OCOM, TINT64}: ssa.OpCom64,
936 opAndType{OCOM, TUINT64}: ssa.OpCom64,
938 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
939 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
940 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
941 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
943 opAndType{OMUL, TINT8}: ssa.OpMul8,
944 opAndType{OMUL, TUINT8}: ssa.OpMul8,
945 opAndType{OMUL, TINT16}: ssa.OpMul16,
946 opAndType{OMUL, TUINT16}: ssa.OpMul16,
947 opAndType{OMUL, TINT32}: ssa.OpMul32,
948 opAndType{OMUL, TUINT32}: ssa.OpMul32,
949 opAndType{OMUL, TINT64}: ssa.OpMul64,
950 opAndType{OMUL, TUINT64}: ssa.OpMul64,
951 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
952 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
954 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
955 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
957 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
958 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
959 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
960 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
961 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
962 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
964 opAndType{ODIV, TINT8}: ssa.OpDiv8,
965 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
966 opAndType{ODIV, TINT16}: ssa.OpDiv16,
967 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
968 opAndType{ODIV, TINT32}: ssa.OpDiv32,
969 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
970 opAndType{ODIV, TINT64}: ssa.OpDiv64,
971 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
973 opAndType{OMOD, TINT8}: ssa.OpMod8,
974 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
975 opAndType{OMOD, TINT16}: ssa.OpMod16,
976 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
977 opAndType{OMOD, TINT32}: ssa.OpMod32,
978 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
979 opAndType{OMOD, TINT64}: ssa.OpMod64,
980 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
982 opAndType{OAND, TINT8}: ssa.OpAnd8,
983 opAndType{OAND, TUINT8}: ssa.OpAnd8,
984 opAndType{OAND, TINT16}: ssa.OpAnd16,
985 opAndType{OAND, TUINT16}: ssa.OpAnd16,
986 opAndType{OAND, TINT32}: ssa.OpAnd32,
987 opAndType{OAND, TUINT32}: ssa.OpAnd32,
988 opAndType{OAND, TINT64}: ssa.OpAnd64,
989 opAndType{OAND, TUINT64}: ssa.OpAnd64,
991 opAndType{OOR, TINT8}: ssa.OpOr8,
992 opAndType{OOR, TUINT8}: ssa.OpOr8,
993 opAndType{OOR, TINT16}: ssa.OpOr16,
994 opAndType{OOR, TUINT16}: ssa.OpOr16,
995 opAndType{OOR, TINT32}: ssa.OpOr32,
996 opAndType{OOR, TUINT32}: ssa.OpOr32,
997 opAndType{OOR, TINT64}: ssa.OpOr64,
998 opAndType{OOR, TUINT64}: ssa.OpOr64,
1000 opAndType{OXOR, TINT8}: ssa.OpXor8,
1001 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1002 opAndType{OXOR, TINT16}: ssa.OpXor16,
1003 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1004 opAndType{OXOR, TINT32}: ssa.OpXor32,
1005 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1006 opAndType{OXOR, TINT64}: ssa.OpXor64,
1007 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1009 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1010 opAndType{OEQ, TINT8}: ssa.OpEq8,
1011 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1012 opAndType{OEQ, TINT16}: ssa.OpEq16,
1013 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1014 opAndType{OEQ, TINT32}: ssa.OpEq32,
1015 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1016 opAndType{OEQ, TINT64}: ssa.OpEq64,
1017 opAndType{OEQ, TUINT64}: ssa.OpEq64,
1018 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1019 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
1020 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1021 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1022 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
1023 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
1024 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1025 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
1026 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1027 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
1029 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1030 opAndType{ONE, TINT8}: ssa.OpNeq8,
1031 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1032 opAndType{ONE, TINT16}: ssa.OpNeq16,
1033 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1034 opAndType{ONE, TINT32}: ssa.OpNeq32,
1035 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1036 opAndType{ONE, TINT64}: ssa.OpNeq64,
1037 opAndType{ONE, TUINT64}: ssa.OpNeq64,
1038 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1039 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
1040 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1041 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1042 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
1043 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
1044 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1045 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
1046 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1047 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
1049 opAndType{OLT, TINT8}: ssa.OpLess8,
1050 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1051 opAndType{OLT, TINT16}: ssa.OpLess16,
1052 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1053 opAndType{OLT, TINT32}: ssa.OpLess32,
1054 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1055 opAndType{OLT, TINT64}: ssa.OpLess64,
1056 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1057 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1058 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
1060 opAndType{OGT, TINT8}: ssa.OpGreater8,
1061 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1062 opAndType{OGT, TINT16}: ssa.OpGreater16,
1063 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1064 opAndType{OGT, TINT32}: ssa.OpGreater32,
1065 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1066 opAndType{OGT, TINT64}: ssa.OpGreater64,
1067 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1068 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1069 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
1071 opAndType{OLE, TINT8}: ssa.OpLeq8,
1072 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1073 opAndType{OLE, TINT16}: ssa.OpLeq16,
1074 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1075 opAndType{OLE, TINT32}: ssa.OpLeq32,
1076 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1077 opAndType{OLE, TINT64}: ssa.OpLeq64,
1078 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1079 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1080 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
1082 opAndType{OGE, TINT8}: ssa.OpGeq8,
1083 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1084 opAndType{OGE, TINT16}: ssa.OpGeq16,
1085 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1086 opAndType{OGE, TINT32}: ssa.OpGeq32,
1087 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1088 opAndType{OGE, TINT64}: ssa.OpGeq64,
1089 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1090 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1091 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
1093 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1094 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1095 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1096 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
1098 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
1101 func (s *state) concreteEtype(t *Type) EType {
1107 if s.config.IntSize == 8 {
1112 if s.config.IntSize == 8 {
1117 if s.config.PtrSize == 8 {
1124 func (s *state) ssaOp(op Op, t *Type) ssa.Op {
1125 etype := s.concreteEtype(t)
1126 x, ok := opToSSA[opAndType{op, etype}]
1128 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
1133 func floatForComplex(t *Type) *Type {
1135 return Types[TFLOAT32]
1137 return Types[TFLOAT64]
1141 type opAndTwoTypes struct {
1147 type twoTypes struct {
1152 type twoOpsAndType struct {
1155 intermediateType EType
1158 var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1160 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1161 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1162 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1163 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1165 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1166 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1167 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1168 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1170 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1171 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1172 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1173 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1175 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1176 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1177 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1178 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1180 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1181 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1182 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1183 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1185 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1186 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1187 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1188 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1190 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1191 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1192 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1193 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1195 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1196 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1197 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1198 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1201 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1202 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1203 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1204 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1207 var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1208 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1209 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1210 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1211 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1212 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1213 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1214 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1215 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1217 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1218 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1219 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1220 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1221 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1222 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1223 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1224 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1226 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1227 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1228 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1229 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1230 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1231 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1232 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1233 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1235 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1236 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1237 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1238 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1239 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1240 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1241 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1242 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1244 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1245 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1246 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1247 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1248 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1249 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1250 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1251 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1253 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1254 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1255 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1256 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1257 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1258 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1259 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1260 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1262 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1263 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1264 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1265 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1266 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1267 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1268 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1269 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1271 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1272 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1273 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1274 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1275 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1276 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1277 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1278 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1281 func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
1282 etype1 := s.concreteEtype(t)
1283 etype2 := s.concreteEtype(u)
1284 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1286 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
1291 func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
1292 etype1 := s.concreteEtype(t)
1293 x, ok := opToSSA[opAndType{op, etype1}]
1295 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
1300 // expr converts the expression n to ssa, adds it to s and returns the ssa result.
1301 func (s *state) expr(n *Node) *ssa.Value {
1302 s.pushLine(n.Lineno)
1308 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
1309 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
1311 addr := s.addr(n, false)
1312 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
1314 if n.Class == PFUNC {
1315 // "value" of a function is the address of the function's closure
1316 sym := funcsym(n.Sym)
1317 aux := &ssa.ExternSymbol{n.Type, sym}
1318 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
1321 return s.variable(n, n.Type)
1323 addr := s.addr(n, false)
1324 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1326 addr := s.addr(n, false)
1327 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1329 switch n.Val().Ctype() {
1331 i := Mpgetfix(n.Val().U.(*Mpint))
1332 switch n.Type.Size() {
1334 return s.constInt8(n.Type, int8(i))
1336 return s.constInt16(n.Type, int16(i))
1338 return s.constInt32(n.Type, int32(i))
1340 return s.constInt64(n.Type, i)
1342 s.Fatalf("bad integer size %d", n.Type.Size())
1346 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1348 v := s.constBool(n.Val().U.(bool))
1349 // For some reason the frontend gets the line numbers of
1350 // CTBOOL literals totally wrong. Fix it here by grabbing
1351 // the line number of the enclosing AST node.
1352 if len(s.line) >= 2 {
1353 v.Line = s.line[len(s.line)-2]
1360 return s.entryNewValue0(ssa.OpConstSlice, t)
1361 case t.IsInterface():
1362 return s.entryNewValue0(ssa.OpConstInterface, t)
1364 return s.entryNewValue0(ssa.OpConstNil, t)
1367 f := n.Val().U.(*Mpflt)
1368 switch n.Type.Size() {
1370 return s.constFloat32(n.Type, mpgetflt32(f))
1372 return s.constFloat64(n.Type, mpgetflt(f))
1374 s.Fatalf("bad float size %d", n.Type.Size())
1378 c := n.Val().U.(*Mpcplx)
1381 switch n.Type.Size() {
1384 pt := Types[TFLOAT32]
1385 return s.newValue2(ssa.OpComplexMake, n.Type,
1386 s.constFloat32(pt, mpgetflt32(r)),
1387 s.constFloat32(pt, mpgetflt32(i)))
1391 pt := Types[TFLOAT64]
1392 return s.newValue2(ssa.OpComplexMake, n.Type,
1393 s.constFloat64(pt, mpgetflt(r)),
1394 s.constFloat64(pt, mpgetflt(i)))
1397 s.Fatalf("bad float size %d", n.Type.Size())
1402 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
1409 // Assume everything will work out, so set up our return value.
1410 // Anything interesting that happens from here is a fatal.
1413 // Special case for not confusing GC and liveness.
1414 // We don't want pointers accidentally classified
1415 // as not-pointers or vice-versa because of copy
1417 if to.IsPtr() != from.IsPtr() {
1418 return s.newValue2(ssa.OpConvert, to, x, s.mem())
1421 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1424 if to.Etype == TFUNC && from.IsPtr() {
1428 // named <--> unnamed type or typed <--> untyped const
1429 if from.Etype == to.Etype {
1433 // unsafe.Pointer <--> *T
1434 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1440 if from.Width != to.Width {
1441 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1444 if etypesign(from.Etype) != etypesign(to.Etype) {
1445 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
1450 // These appear to be fine, but they fail the
1451 // integer constraint below, so okay them here.
1452 // Sample non-integer conversion: map[string]string -> *uint8
1456 if etypesign(from.Etype) == 0 {
1457 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1461 // integer, same width, same sign
1466 ft := n.Left.Type // from type
1467 tt := n.Type // to type
1468 if ft.IsInteger() && tt.IsInteger() {
1470 if tt.Size() == ft.Size() {
1472 } else if tt.Size() < ft.Size() {
1474 switch 10*ft.Size() + tt.Size() {
1476 op = ssa.OpTrunc16to8
1478 op = ssa.OpTrunc32to8
1480 op = ssa.OpTrunc32to16
1482 op = ssa.OpTrunc64to8
1484 op = ssa.OpTrunc64to16
1486 op = ssa.OpTrunc64to32
1488 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1490 } else if ft.IsSigned() {
1492 switch 10*ft.Size() + tt.Size() {
1494 op = ssa.OpSignExt8to16
1496 op = ssa.OpSignExt8to32
1498 op = ssa.OpSignExt8to64
1500 op = ssa.OpSignExt16to32
1502 op = ssa.OpSignExt16to64
1504 op = ssa.OpSignExt32to64
1506 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1510 switch 10*ft.Size() + tt.Size() {
1512 op = ssa.OpZeroExt8to16
1514 op = ssa.OpZeroExt8to32
1516 op = ssa.OpZeroExt8to64
1518 op = ssa.OpZeroExt16to32
1520 op = ssa.OpZeroExt16to64
1522 op = ssa.OpZeroExt32to64
1524 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1527 return s.newValue1(op, n.Type, x)
1530 if ft.IsFloat() || tt.IsFloat() {
1531 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1533 s.Fatalf("weird float conversion %s -> %s", ft, tt)
1535 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1537 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1538 // normal case, not tripping over unsigned 64
1539 if op1 == ssa.OpCopy {
1540 if op2 == ssa.OpCopy {
1543 return s.newValue1(op2, n.Type, x)
1545 if op2 == ssa.OpCopy {
1546 return s.newValue1(op1, n.Type, x)
1548 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1550 // Tricky 64-bit unsigned cases.
1552 // therefore tt is float32 or float64, and ft is also unsigned
1554 return s.uint64Tofloat32(n, x, ft, tt)
1557 return s.uint64Tofloat64(n, x, ft, tt)
1559 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
1561 // therefore ft is float32 or float64, and tt is unsigned integer
1563 return s.float32ToUint64(n, x, ft, tt)
1566 return s.float64ToUint64(n, x, ft, tt)
1568 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1572 if ft.IsComplex() && tt.IsComplex() {
1574 if ft.Size() == tt.Size() {
1576 } else if ft.Size() == 8 && tt.Size() == 16 {
1577 op = ssa.OpCvt32Fto64F
1578 } else if ft.Size() == 16 && tt.Size() == 8 {
1579 op = ssa.OpCvt64Fto32F
1581 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1583 ftp := floatForComplex(ft)
1584 ttp := floatForComplex(tt)
1585 return s.newValue2(ssa.OpComplexMake, tt,
1586 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1587 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1590 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
1594 res, _ := s.dottype(n, false)
1598 case OLT, OEQ, ONE, OLE, OGE, OGT:
1600 b := s.expr(n.Right)
1601 if n.Left.Type.IsComplex() {
1602 pt := floatForComplex(n.Left.Type)
1603 op := s.ssaOp(OEQ, pt)
1604 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1605 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1606 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1611 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1613 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1616 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
1619 b := s.expr(n.Right)
1620 if n.Type.IsComplex() {
1621 mulop := ssa.OpMul64F
1622 addop := ssa.OpAdd64F
1623 subop := ssa.OpSub64F
1624 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1625 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1627 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1628 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1629 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1630 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1632 if pt != wt { // Widen for calculation
1633 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1634 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1635 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1636 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1639 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1640 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1642 if pt != wt { // Narrow to store back
1643 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1644 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1647 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1649 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1653 b := s.expr(n.Right)
1654 if n.Type.IsComplex() {
1655 // TODO this is not executed because the front-end substitutes a runtime call.
1656 // That probably ought to change; with modest optimization the widen/narrow
1657 // conversions could all be elided in larger expression trees.
1658 mulop := ssa.OpMul64F
1659 addop := ssa.OpAdd64F
1660 subop := ssa.OpSub64F
1661 divop := ssa.OpDiv64F
1662 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1663 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1665 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1666 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1667 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1668 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1670 if pt != wt { // Widen for calculation
1671 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1672 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1673 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1674 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1677 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1678 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1679 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1681 // TODO not sure if this is best done in wide precision or narrow
1682 // Double-rounding might be an issue.
1683 // Note that the pre-SSA implementation does the entire calculation
1684 // in wide format, so wide is compatible.
1685 xreal = s.newValue2(divop, wt, xreal, denom)
1686 ximag = s.newValue2(divop, wt, ximag, denom)
1688 if pt != wt { // Narrow to store back
1689 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1690 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1692 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1694 if n.Type.IsFloat() {
1695 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1697 // do a size-appropriate check for zero
1698 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1699 s.check(cmp, panicdivide)
1700 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1704 b := s.expr(n.Right)
1705 // do a size-appropriate check for zero
1706 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1707 s.check(cmp, panicdivide)
1708 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1711 b := s.expr(n.Right)
1712 if n.Type.IsComplex() {
1713 pt := floatForComplex(n.Type)
1714 op := s.ssaOp(n.Op, pt)
1715 return s.newValue2(ssa.OpComplexMake, n.Type,
1716 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1717 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1719 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1720 case OAND, OOR, OHMUL, OXOR:
1722 b := s.expr(n.Right)
1723 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1726 b := s.expr(n.Right)
1727 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
1731 if i <= 0 || i >= n.Type.Size()*8 {
1732 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1734 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
1735 case OANDAND, OOROR:
1736 // To implement OANDAND (and OOROR), we introduce a
1737 // new temporary variable to hold the result. The
1738 // variable is associated with the OANDAND node in the
1739 // s.vars table (normally variables are only
1740 // associated with ONAME nodes). We convert
1747 // Using var in the subsequent block introduces the
1748 // necessary phi variable.
1749 el := s.expr(n.Left)
1753 b.Kind = ssa.BlockIf
1755 // In theory, we should set b.Likely here based on context.
1756 // However, gc only gives us likeliness hints
1757 // in a single place, for plain OIF statements,
1758 // and passing around context is finnicky, so don't bother for now.
1760 bRight := s.f.NewBlock(ssa.BlockPlain)
1761 bResult := s.f.NewBlock(ssa.BlockPlain)
1762 if n.Op == OANDAND {
1764 b.AddEdgeTo(bResult)
1765 } else if n.Op == OOROR {
1766 b.AddEdgeTo(bResult)
1770 s.startBlock(bRight)
1771 er := s.expr(n.Right)
1775 b.AddEdgeTo(bResult)
1777 s.startBlock(bResult)
1778 return s.variable(n, Types[TBOOL])
1781 i := s.expr(n.Right)
1782 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
1787 if n.Type.IsComplex() {
1788 tp := floatForComplex(n.Type)
1789 negop := s.ssaOp(n.Op, tp)
1790 return s.newValue2(ssa.OpComplexMake, n.Type,
1791 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1792 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1794 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1795 case ONOT, OCOM, OSQRT:
1797 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
1800 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
1802 return s.expr(n.Left)
1805 return s.addr(n.Left, n.Bounded)
1808 if int(n.Reg) != Thearch.REGSP {
1809 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1812 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1813 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1818 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1824 return s.newValue1I(ssa.OpStructSelect, n.Type, fieldIdx(n), v)
1826 p := s.addr(n, false)
1827 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1832 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
1833 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
1837 case n.Left.Type.IsString():
1839 i := s.expr(n.Right)
1840 i = s.extendIndex(i)
1842 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1843 s.boundsCheck(i, len)
1845 ptrtyp := Ptrto(Types[TUINT8])
1846 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1847 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1848 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1849 case n.Left.Type.IsSlice():
1850 p := s.addr(n, false)
1851 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1852 case n.Left.Type.IsArray():
1853 // TODO: fix when we can SSA arrays of length 1.
1854 p := s.addr(n, false)
1855 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1857 s.Fatalf("bad type for index %v", n.Left.Type)
1863 case n.Left.Type.IsSlice():
1864 op := ssa.OpSliceLen
1868 return s.newValue1(op, Types[TINT], s.expr(n.Left))
1869 case n.Left.Type.IsString(): // string; not reachable for OCAP
1870 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
1871 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1872 return s.referenceTypeBuiltin(n, s.expr(n.Left))
1874 return s.constInt(Types[TINT], n.Left.Type.Bound)
1879 if n.Left.Type.IsSlice() {
1880 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1882 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1887 return s.newValue1(ssa.OpITab, n.Type, a)
1890 tab := s.expr(n.Left)
1891 data := s.expr(n.Right)
1892 // The frontend allows putting things like struct{*byte} in
1893 // the data portion of an eface. But we don't want struct{*byte}
1894 // as a register type because (among other reasons) the liveness
1895 // analysis is confused by the "fat" variables that result from
1896 // such types being spilled.
1897 // So here we ensure that we are selecting the underlying pointer
1898 // when we build an eface.
1899 // TODO: get rid of this now that structs can be SSA'd?
1900 for !data.Type.IsPtr() {
1902 case data.Type.IsArray():
1903 data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
1904 case data.Type.IsStruct():
1905 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1906 f := data.Type.FieldType(i)
1908 // eface type could also be struct{p *byte; q [0]int}
1911 data = s.newValue1I(ssa.OpStructSelect, f, i, data)
1915 s.Fatalf("type being put into an eface isn't a pointer")
1918 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1920 case OSLICE, OSLICEARR:
1923 if n.Right.Left != nil {
1924 i = s.extendIndex(s.expr(n.Right.Left))
1926 if n.Right.Right != nil {
1927 j = s.extendIndex(s.expr(n.Right.Right))
1929 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1930 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1934 if n.Right.Left != nil {
1935 i = s.extendIndex(s.expr(n.Right.Left))
1937 if n.Right.Right != nil {
1938 j = s.extendIndex(s.expr(n.Right.Right))
1940 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1941 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1942 case OSLICE3, OSLICE3ARR:
1945 if n.Right.Left != nil {
1946 i = s.extendIndex(s.expr(n.Right.Left))
1948 j := s.extendIndex(s.expr(n.Right.Right.Left))
1949 k := s.extendIndex(s.expr(n.Right.Right.Right))
1950 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1951 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
1953 case OCALLFUNC, OCALLINTER, OCALLMETH:
1954 a := s.call(n, callNormal)
1955 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
1958 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
1961 // append(s, e1, e2, e3). Compile like:
1963 // newlen := len + 3
1964 // if newlen > s.cap {
1965 // ptr,_,cap = growslice(s, newlen)
1968 // *(ptr+len+1) = e2
1969 // *(ptr+len+2) = e3
1970 // makeslice(ptr,newlen,cap)
1976 slice := s.expr(n.List.N)
1978 // Allocate new blocks
1979 grow := s.f.NewBlock(ssa.BlockPlain)
1980 assign := s.f.NewBlock(ssa.BlockPlain)
1982 // Decide if we need to grow
1983 nargs := int64(count(n.List) - 1)
1984 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
1985 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
1986 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
1987 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
1988 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
1992 b.Kind = ssa.BlockIf
1993 b.Likely = ssa.BranchUnlikely
2000 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
2002 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
2004 s.vars[&ptrVar] = r[0]
2005 // Note: we don't need to read r[1], the result's length. It will be nl.
2006 // (or maybe we should, we just have to spill/restore nl otherwise?)
2007 s.vars[&capVar] = r[2]
2011 // assign new elements to slots
2012 s.startBlock(assign)
2015 args := make([]*ssa.Value, 0, nargs)
2016 store := make([]bool, 0, nargs)
2017 for l := n.List.Next; l != nil; l = l.Next {
2018 if canSSAType(l.N.Type) {
2019 args = append(args, s.expr(l.N))
2020 store = append(store, true)
2022 args = append(args, s.addr(l.N, false))
2023 store = append(store, false)
2027 p = s.variable(&ptrVar, pt) // generates phi for ptr
2028 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
2029 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
2030 // TODO: just one write barrier call for all of these writes?
2031 // TODO: maybe just one writeBarrier.enabled check?
2032 for i, arg := range args {
2033 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
2035 if haspointers(et) {
2036 s.insertWBstore(et, addr, arg, n.Lineno)
2038 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2041 if haspointers(et) {
2042 s.insertWBmove(et, addr, arg, n.Lineno)
2044 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2050 delete(s.vars, &ptrVar)
2051 delete(s.vars, &capVar)
2052 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2055 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
2060 // condBranch evaluates the boolean expression cond and branches to yes
2061 // if cond is true and no if cond is false.
2062 // This function is intended to handle && and || better than just calling
2063 // s.expr(cond) and branching on the result.
2064 func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2065 if cond.Op == OANDAND {
2066 mid := s.f.NewBlock(ssa.BlockPlain)
2067 s.stmtList(cond.Ninit)
2068 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2070 s.condBranch(cond.Right, yes, no, likely)
2072 // Note: if likely==1, then both recursive calls pass 1.
2073 // If likely==-1, then we don't have enough information to decide
2074 // whether the first branch is likely or not. So we pass 0 for
2075 // the likeliness of the first branch.
2076 // TODO: have the frontend give us branch prediction hints for
2077 // OANDAND and OOROR nodes (if it ever has such info).
2079 if cond.Op == OOROR {
2080 mid := s.f.NewBlock(ssa.BlockPlain)
2081 s.stmtList(cond.Ninit)
2082 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2084 s.condBranch(cond.Right, yes, no, likely)
2086 // Note: if likely==-1, then both recursive calls pass -1.
2087 // If likely==1, then we don't have enough info to decide
2088 // the likelihood of the first branch.
2090 if cond.Op == ONOT {
2091 s.stmtList(cond.Ninit)
2092 s.condBranch(cond.Left, no, yes, -likely)
2097 b.Kind = ssa.BlockIf
2099 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2104 // assign does left = right.
2105 // Right has already been evaluated to ssa, left has not.
2106 // If deref is true, then we do left = *right instead (and right has already been nil-checked).
2107 // If deref is true and right == nil, just do left = 0.
2108 // Include a write barrier if wb is true.
2109 func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32) {
2110 if left.Op == ONAME && isblank(left) {
2117 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2119 if left.Op == ODOT {
2120 // We're assigning to a field of an ssa-able value.
2121 // We need to build a new structure with the new value for the
2122 // field we're assigning and the old values for the other fields.
2124 // type T struct {a, b, c int}
2127 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2129 // Grab information about the structure type.
2132 idx := fieldIdx(left)
2134 // Grab old value of structure.
2135 old := s.expr(left.Left)
2137 // Make new structure.
2138 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2140 // Add fields as args.
2141 for i := int64(0); i < nf; i++ {
2145 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), i, old))
2149 // Recursively assign the new value we've made to the base of the dot op.
2150 s.assign(left.Left, new, false, false, line)
2151 // TODO: do we need to update named values here?
2154 // Update variable assignment.
2155 s.vars[left] = right
2156 s.addNamedValue(left, right)
2159 // Left is not ssa-able. Compute its address.
2160 addr := s.addr(left, false)
2161 if left.Op == ONAME {
2162 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
2165 // Treat as a mem->mem move.
2167 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2171 s.insertWBmove(t, addr, right, line)
2174 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2177 // Treat as a store.
2179 s.insertWBstore(t, addr, right, line)
2182 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
2185 // zeroVal returns the zero value for type t.
2186 func (s *state) zeroVal(t *Type) *ssa.Value {
2191 return s.constInt8(t, 0)
2193 return s.constInt16(t, 0)
2195 return s.constInt32(t, 0)
2197 return s.constInt64(t, 0)
2199 s.Fatalf("bad sized integer type %s", t)
2204 return s.constFloat32(t, 0)
2206 return s.constFloat64(t, 0)
2208 s.Fatalf("bad sized float type %s", t)
2213 z := s.constFloat32(Types[TFLOAT32], 0)
2214 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2216 z := s.constFloat64(Types[TFLOAT64], 0)
2217 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
2219 s.Fatalf("bad sized complex type %s", t)
2223 return s.entryNewValue0A(ssa.OpConstString, t, "")
2225 return s.entryNewValue0(ssa.OpConstNil, t)
2227 return s.constBool(false)
2228 case t.IsInterface():
2229 return s.entryNewValue0(ssa.OpConstInterface, t)
2231 return s.entryNewValue0(ssa.OpConstSlice, t)
2234 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
2235 for i := int64(0); i < n; i++ {
2236 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2240 s.Unimplementedf("zero for type %v not implemented", t)
2247 callNormal callKind = iota
2252 // Calls the function n using the specified call type.
2253 // Returns the address of the return value (or nil if none).
2254 func (s *state) call(n *Node, k callKind) *ssa.Value {
2255 var sym *Sym // target symbol (if static)
2256 var closure *ssa.Value // ptr to closure to run (if dynamic)
2257 var codeptr *ssa.Value // ptr to target code (if dynamic)
2258 var rcvr *ssa.Value // receiver to set
2262 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2266 closure = s.expr(fn)
2268 if fn.Op != ODOTMETH {
2269 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2271 if fn.Right.Op != ONAME {
2272 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2274 if k == callNormal {
2280 closure = s.expr(&n2)
2281 // Note: receiver is already assigned in n.List, so we don't
2282 // want to set it here.
2284 if fn.Op != ODOTINTER {
2285 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2287 i := s.expr(fn.Left)
2288 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2289 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2290 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2291 if k == callNormal {
2292 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2296 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2299 stksize := fn.Type.Argwid // includes receiver
2301 // Run all argument assignments. The arg slots have already
2302 // been offset by the appropriate amount (+2*widthptr for go/defer,
2303 // +widthptr for interface calls).
2304 // For OCALLMETH, the receiver is set in these statements.
2307 // Set receiver (for interface calls)
2309 argStart := Ctxt.FixedFrameSize()
2310 if k != callNormal {
2311 argStart += int64(2 * Widthptr)
2313 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
2314 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
2318 if k != callNormal {
2319 // Write argsize and closure (args to Newproc/Deferproc).
2320 argsize := s.constInt32(Types[TUINT32], int32(stksize))
2321 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
2322 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
2323 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
2324 stksize += 2 * int64(Widthptr)
2328 bNext := s.f.NewBlock(ssa.BlockPlain)
2331 case k == callDefer:
2332 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2334 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2335 case closure != nil:
2336 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2337 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2338 case codeptr != nil:
2339 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2341 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2343 Fatalf("bad call type %s %v", opnames[n.Op], n)
2345 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2347 // Finish call block
2348 s.vars[&memVar] = call
2350 b.Kind = ssa.BlockCall
2354 // Start exit block, find address of result.
2357 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2358 if fp == nil || k != callNormal {
2359 // call has no return value. Continue with the next statement.
2362 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
2365 // etypesign returns the signed-ness of e, for integer/pointer etypes.
2366 // -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
2367 func etypesign(e EType) int8 {
2369 case TINT8, TINT16, TINT32, TINT64, TINT:
2371 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2377 // lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2378 // This improves the effectiveness of cse by using the same Aux values for the
2380 func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2383 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2384 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2385 // these are the only valid types
2388 if lsym, ok := s.varsyms[n]; ok {
2396 // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
2397 // The value that the returned Value represents is guaranteed to be non-nil.
2398 // If bounded is true then this address does not require a nil check for its operand
2399 // even if that would otherwise be implied.
2400 func (s *state) addr(n *Node, bounded bool) *ssa.Value {
2407 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
2408 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
2409 // TODO: Make OpAddr use AuxInt as well as Aux.
2411 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2420 if n.String() == ".fp" {
2421 // Special arg that points to the frame pointer.
2422 // (Used by the race detector, others?)
2423 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2424 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2426 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2429 // We need to regenerate the address of autos
2430 // at every use. This prevents LEA instructions
2431 // from occurring before the corresponding VarDef
2432 // op and confusing the liveness analysis into thinking
2433 // the variable is live at function entry.
2434 // TODO: I'm not sure if this really works or we're just
2435 // getting lucky. We might need a real dependency edge
2436 // between vardef and addr ops.
2437 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
2438 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2439 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
2440 // ensure that we reuse symbols for out parameters so
2441 // that cse works on their addresses
2442 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2443 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
2444 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
2445 return s.expr(n.Name.Heapaddr)
2447 s.Unimplementedf("variable address class %v not implemented", n.Class)
2451 // indirect off a register
2452 // used for storing/loading arguments/returns to/from callees
2453 if int(n.Reg) != Thearch.REGSP {
2454 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2457 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
2459 if n.Left.Type.IsSlice() {
2461 i := s.expr(n.Right)
2462 i = s.extendIndex(i)
2463 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
2465 s.boundsCheck(i, len)
2467 p := s.newValue1(ssa.OpSlicePtr, t, a)
2468 return s.newValue2(ssa.OpPtrIndex, t, p, i)
2470 a := s.addr(n.Left, bounded)
2471 i := s.expr(n.Right)
2472 i = s.extendIndex(i)
2473 len := s.constInt(Types[TINT], n.Left.Type.Bound)
2475 s.boundsCheck(i, len)
2477 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
2486 p := s.addr(n.Left, bounded)
2487 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2493 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
2495 return s.newValue2(ssa.OpAddPtr, t,
2496 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
2497 s.constInt(Types[TINT], n.Xoffset))
2500 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2501 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2504 // Recover original offset to address passed-in param value.
2506 original_p.Xoffset = n.Xoffset
2507 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
2508 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2510 addr := s.addr(n.Left, bounded)
2511 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
2512 case OCALLFUNC, OCALLINTER, OCALLMETH:
2513 return s.call(n, callNormal)
2516 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
2521 // canSSA reports whether n is SSA-able.
2522 // n must be an ONAME (or an ODOT sequence with an ONAME base).
2523 func canSSA(n *Node) bool {
2533 if n.Class&PHEAP != 0 {
2537 case PEXTERN, PPARAMOUT, PPARAMREF:
2540 if n.Class == PPARAM && n.String() == ".this" {
2541 // wrappers generated by genwrapper need to update
2542 // the .this pointer in place.
2545 return canSSAType(n.Type)
2546 // TODO: try to make more variables SSAable?
2549 // canSSA reports whether variables of type t are SSA-able.
2550 func canSSAType(t *Type) bool {
2552 if t.Width > int64(4*Widthptr) {
2553 // 4*Widthptr is an arbitrary constant. We want it
2554 // to be at least 3*Widthptr so slices can be registerized.
2555 // Too big and we'll introduce too much register pressure.
2563 // We can't do arrays because dynamic indexing is
2564 // not supported on SSA variables.
2565 // TODO: maybe allow if length is <=1? All indexes
2566 // are constant? Might be good for the arrays
2567 // introduced by the compiler for variadic functions.
2570 if countfield(t) > ssa.MaxStruct {
2573 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2574 if !canSSAType(t1.Type) {
2584 // nilCheck generates nil pointer checking code.
2585 // Starts a new block on return, unless nil checks are disabled.
2586 // Used only for automatically inserted nil checks,
2587 // not for user code like 'x != nil'.
2588 func (s *state) nilCheck(ptr *ssa.Value) {
2589 if Disable_checknil != 0 {
2592 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
2594 b.Kind = ssa.BlockCheck
2596 bNext := s.f.NewBlock(ssa.BlockPlain)
2601 // boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2602 // Starts a new block on return.
2603 func (s *state) boundsCheck(idx, len *ssa.Value) {
2604 if Debug['B'] != 0 {
2607 // TODO: convert index to full width?
2608 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2611 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
2612 s.check(cmp, Panicindex)
2615 // sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2616 // Starts a new block on return.
2617 func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2618 if Debug['B'] != 0 {
2621 // TODO: convert index to full width?
2622 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2625 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
2626 s.check(cmp, panicslice)
2629 // If cmp (a bool) is true, panic using the given function.
2630 func (s *state) check(cmp *ssa.Value, fn *Node) {
2632 b.Kind = ssa.BlockIf
2634 b.Likely = ssa.BranchLikely
2635 bNext := s.f.NewBlock(ssa.BlockPlain)
2636 line := s.peekLine()
2637 bPanic := s.panics[funcLine{fn, line}]
2639 bPanic = s.f.NewBlock(ssa.BlockPlain)
2640 s.panics[funcLine{fn, line}] = bPanic
2641 s.startBlock(bPanic)
2642 // The panic call takes/returns memory to ensure that the right
2643 // memory state is observed if the panic happens.
2644 s.rtcall(fn, false, nil)
2651 // rtcall issues a call to the given runtime function fn with the listed args.
2652 // Returns a slice of results of the given result types.
2653 // The call is added to the end of the current block.
2654 // If returns is false, the block is marked as an exit block.
2655 // If returns is true, the block is marked as a call block. A new block
2656 // is started to load the return values.
2657 func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2658 // Write args to the stack
2659 var off int64 // TODO: arch-dependent starting offset?
2660 for _, arg := range args {
2662 off = Rnd(off, t.Alignment())
2665 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2668 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2671 off = Rnd(off, int64(Widthptr))
2674 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2675 s.vars[&memVar] = call
2680 b.Kind = ssa.BlockExit
2683 if len(results) > 0 {
2684 Fatalf("panic call can't have results")
2688 b.Kind = ssa.BlockCall
2690 bNext := s.f.NewBlock(ssa.BlockPlain)
2695 res := make([]*ssa.Value, len(results))
2696 for i, t := range results {
2697 off = Rnd(off, t.Alignment())
2700 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2702 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2705 off = Rnd(off, int64(Widthptr))
2707 // Remember how much callee stack space we needed.
2713 // insertWBmove inserts the assignment *left = *right including a write barrier.
2714 // t is the type being assigned.
2715 func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
2716 // if writeBarrier.enabled {
2717 // typedmemmove(&t, left, right)
2721 bThen := s.f.NewBlock(ssa.BlockPlain)
2722 bElse := s.f.NewBlock(ssa.BlockPlain)
2723 bEnd := s.f.NewBlock(ssa.BlockPlain)
2725 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2726 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2727 // TODO: select the .enabled field. It is currently first, so not needed for now.
2728 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2730 b.Kind = ssa.BlockIf
2731 b.Likely = ssa.BranchUnlikely
2737 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
2738 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2739 s.endBlock().AddEdgeTo(bEnd)
2742 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2743 s.endBlock().AddEdgeTo(bEnd)
2748 Warnl(int(line), "write barrier")
2752 // insertWBstore inserts the assignment *left = right including a write barrier.
2753 // t is the type being assigned.
2754 func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32) {
2755 // store scalar fields
2756 // if writeBarrier.enabled {
2757 // writebarrierptr for pointer fields
2759 // store pointer fields
2762 s.storeTypeScalars(t, left, right)
2764 bThen := s.f.NewBlock(ssa.BlockPlain)
2765 bElse := s.f.NewBlock(ssa.BlockPlain)
2766 bEnd := s.f.NewBlock(ssa.BlockPlain)
2768 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
2769 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
2770 // TODO: select the .enabled field. It is currently first, so not needed for now.
2771 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2773 b.Kind = ssa.BlockIf
2774 b.Likely = ssa.BranchUnlikely
2779 // Issue write barriers for pointer writes.
2781 s.storeTypePtrsWB(t, left, right)
2782 s.endBlock().AddEdgeTo(bEnd)
2784 // Issue regular stores for pointer writes.
2786 s.storeTypePtrs(t, left, right)
2787 s.endBlock().AddEdgeTo(bEnd)
2792 Warnl(int(line), "write barrier")
2796 // do *left = right for all scalar (non-pointer) parts of t.
2797 func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value) {
2799 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
2800 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
2801 case t.IsPtr() || t.IsMap() || t.IsChan():
2802 // no scalar fields.
2804 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
2805 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2806 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2808 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
2809 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
2810 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2811 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2812 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
2813 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
2814 case t.IsInterface():
2815 // itab field doesn't need a write barrier (even though it is a pointer).
2816 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
2817 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
2820 for i := int64(0); i < n; i++ {
2821 ft := t.FieldType(i)
2822 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2823 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2824 s.storeTypeScalars(ft.(*Type), addr, val)
2827 s.Fatalf("bad write barrier type %s", t)
2831 // do *left = right for all pointer parts of t.
2832 func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
2834 case t.IsPtr() || t.IsMap() || t.IsChan():
2835 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
2837 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2838 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2840 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2841 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2842 case t.IsInterface():
2843 // itab field is treated as a scalar.
2844 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2845 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2846 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
2849 for i := int64(0); i < n; i++ {
2850 ft := t.FieldType(i)
2851 if !haspointers(ft.(*Type)) {
2854 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2855 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2856 s.storeTypePtrs(ft.(*Type), addr, val)
2859 s.Fatalf("bad write barrier type %s", t)
2863 // do *left = right with a write barrier for all pointer parts of t.
2864 func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
2866 case t.IsPtr() || t.IsMap() || t.IsChan():
2867 s.rtcall(writebarrierptr, true, nil, left, right)
2869 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2870 s.rtcall(writebarrierptr, true, nil, left, ptr)
2872 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2873 s.rtcall(writebarrierptr, true, nil, left, ptr)
2874 case t.IsInterface():
2875 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2876 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2877 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
2880 for i := int64(0); i < n; i++ {
2881 ft := t.FieldType(i)
2882 if !haspointers(ft.(*Type)) {
2885 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2886 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2887 s.storeTypePtrsWB(ft.(*Type), addr, val)
2890 s.Fatalf("bad write barrier type %s", t)
2894 // slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2895 // i,j,k may be nil, in which case they are set to their default value.
2896 // t is a slice, ptr to array, or string type.
2897 func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2903 zero := s.constInt(Types[TINT], 0)
2907 ptrtype = Ptrto(elemtype)
2908 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2909 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2910 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2912 elemtype = Types[TUINT8]
2913 ptrtype = Ptrto(elemtype)
2914 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2915 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2918 if !t.Type.IsArray() {
2919 s.Fatalf("bad ptr to array in slice %v\n", t)
2921 elemtype = t.Type.Type
2922 ptrtype = Ptrto(elemtype)
2925 len = s.constInt(Types[TINT], t.Type.Bound)
2928 s.Fatalf("bad type in slice %v\n", t)
2931 // Set default values
2942 // Panic if slice indices are not in bounds.
2943 s.sliceBoundsCheck(i, j)
2945 s.sliceBoundsCheck(j, k)
2948 s.sliceBoundsCheck(k, cap)
2951 // Generate the following code assuming that indexes are in bounds.
2952 // The conditional is to make sure that we don't generate a slice
2953 // that points to the next object in memory.
2954 // rlen = (Sub64 j i)
2955 // rcap = (Sub64 k i)
2958 // p = (AddPtr ptr (Mul64 low (Const64 size)))
2960 // result = (SliceMake p size)
2961 subOp := s.ssaOp(OSUB, Types[TINT])
2962 neqOp := s.ssaOp(ONE, Types[TINT])
2963 mulOp := s.ssaOp(OMUL, Types[TINT])
2964 rlen := s.newValue2(subOp, Types[TINT], j, i)
2968 // Capacity of the result is unimportant. However, we use
2969 // rcap to test if we've generated a zero-length slice.
2970 // Use length of strings for that.
2975 rcap = s.newValue2(subOp, Types[TINT], k, i)
2978 s.vars[&ptrVar] = ptr
2980 // Generate code to test the resulting slice length.
2981 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
2984 b.Kind = ssa.BlockIf
2985 b.Likely = ssa.BranchLikely
2988 // Generate code for non-zero length slice case.
2989 nz := s.f.NewBlock(ssa.BlockPlain)
2993 if elemtype.Width == 1 {
2996 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
2998 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
3002 merge := s.f.NewBlock(ssa.BlockPlain)
3006 rptr := s.variable(&ptrVar, ptrtype)
3007 delete(s.vars, &ptrVar)
3008 return rptr, rlen, rcap
3011 type u2fcvtTab struct {
3012 geq, cvt2F, and, rsh, or, add ssa.Op
3013 one func(*state, ssa.Type, int64) *ssa.Value
3016 var u64_f64 u2fcvtTab = u2fcvtTab{
3018 cvt2F: ssa.OpCvt64to64F,
3020 rsh: ssa.OpRsh64Ux64,
3023 one: (*state).constInt64,
3026 var u64_f32 u2fcvtTab = u2fcvtTab{
3028 cvt2F: ssa.OpCvt64to32F,
3030 rsh: ssa.OpRsh64Ux64,
3033 one: (*state).constInt64,
3036 // Excess generality on a machine with 64-bit integer registers.
3037 // Not used on AMD64.
3038 var u32_f32 u2fcvtTab = u2fcvtTab{
3040 cvt2F: ssa.OpCvt32to32F,
3042 rsh: ssa.OpRsh32Ux32,
3045 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3046 return s.constInt32(t, int32(x))
3050 func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3051 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3054 func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3055 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3058 func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3060 // result = (floatY) x
3062 // y = uintX(x) ; y = x & 1
3063 // z = uintX(x) ; z = z >> 1
3066 // result = floatY(z)
3067 // result = result + result
3070 // Code borrowed from old code generator.
3071 // What's going on: large 64-bit "unsigned" looks like
3072 // negative number to hardware's integer-to-float
3073 // conversion. However, because the mantissa is only
3074 // 63 bits, we don't need the LSB, so instead we do an
3075 // unsigned right shift (divide by two), convert, and
3076 // double. However, before we do that, we need to be
3077 // sure that we do not lose a "1" if that made the
3078 // difference in the resulting rounding. Therefore, we
3079 // preserve it, and OR (not ADD) it back in. The case
3080 // that matters is when the eleven discarded bits are
3081 // equal to 10000000001; that rounds up, and the 1 cannot
3082 // be lost else it would round down if the LSB of the
3083 // candidate mantissa is 0.
3084 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3086 b.Kind = ssa.BlockIf
3088 b.Likely = ssa.BranchLikely
3090 bThen := s.f.NewBlock(ssa.BlockPlain)
3091 bElse := s.f.NewBlock(ssa.BlockPlain)
3092 bAfter := s.f.NewBlock(ssa.BlockPlain)
3096 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3099 bThen.AddEdgeTo(bAfter)
3103 one := cvttab.one(s, ft, 1)
3104 y := s.newValue2(cvttab.and, ft, x, one)
3105 z := s.newValue2(cvttab.rsh, ft, x, one)
3106 z = s.newValue2(cvttab.or, ft, z, y)
3107 a := s.newValue1(cvttab.cvt2F, tt, z)
3108 a1 := s.newValue2(cvttab.add, tt, a, a)
3111 bElse.AddEdgeTo(bAfter)
3113 s.startBlock(bAfter)
3114 return s.variable(n, n.Type)
3117 // referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3118 func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3119 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3120 s.Fatalf("node must be a map or a channel")
3126 // return *((*int)n)
3128 // return *(((*int)n)+1)
3131 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
3132 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
3134 b.Kind = ssa.BlockIf
3136 b.Likely = ssa.BranchUnlikely
3138 bThen := s.f.NewBlock(ssa.BlockPlain)
3139 bElse := s.f.NewBlock(ssa.BlockPlain)
3140 bAfter := s.f.NewBlock(ssa.BlockPlain)
3142 // length/capacity of a nil map/chan is zero
3145 s.vars[n] = s.zeroVal(lenType)
3147 bThen.AddEdgeTo(bAfter)
3152 // length is stored in the first word for map/chan
3153 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3154 } else if n.Op == OCAP {
3155 // capacity is stored in the second word for chan
3156 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3157 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3159 s.Fatalf("op must be OLEN or OCAP")
3162 bElse.AddEdgeTo(bAfter)
3164 s.startBlock(bAfter)
3165 return s.variable(n, lenType)
3168 type f2uCvtTab struct {
3169 ltf, cvt2U, subf ssa.Op
3170 value func(*state, ssa.Type, float64) *ssa.Value
3173 var f32_u64 f2uCvtTab = f2uCvtTab{
3175 cvt2U: ssa.OpCvt32Fto64,
3177 value: (*state).constFloat32,
3180 var f64_u64 f2uCvtTab = f2uCvtTab{
3182 cvt2U: ssa.OpCvt64Fto64,
3184 value: (*state).constFloat64,
3187 func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3188 return s.floatToUint(&f32_u64, n, x, ft, tt)
3190 func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3191 return s.floatToUint(&f64_u64, n, x, ft, tt)
3194 func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3195 // if x < 9223372036854775808.0 {
3196 // result = uintY(x)
3198 // y = x - 9223372036854775808.0
3200 // result = z | -9223372036854775808
3202 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3203 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3205 b.Kind = ssa.BlockIf
3207 b.Likely = ssa.BranchLikely
3209 bThen := s.f.NewBlock(ssa.BlockPlain)
3210 bElse := s.f.NewBlock(ssa.BlockPlain)
3211 bAfter := s.f.NewBlock(ssa.BlockPlain)
3215 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3218 bThen.AddEdgeTo(bAfter)
3222 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3223 y = s.newValue1(cvttab.cvt2U, tt, y)
3224 z := s.constInt64(tt, -9223372036854775808)
3225 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3228 bElse.AddEdgeTo(bAfter)
3230 s.startBlock(bAfter)
3231 return s.variable(n, n.Type)
3234 // ifaceType returns the value for the word containing the type.
3235 // n is the node for the interface expression.
3236 // v is the corresponding value.
3237 func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3238 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3240 if isnilinter(n.Type) {
3241 // Have *eface. The type is the first word in the struct.
3242 return s.newValue1(ssa.OpITab, byteptr, v)
3246 // The first word in the struct is the *itab.
3247 // If the *itab is nil, return 0.
3248 // Otherwise, the second word in the *itab is the type.
3250 tab := s.newValue1(ssa.OpITab, byteptr, v)
3251 s.vars[&typVar] = tab
3252 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3254 b.Kind = ssa.BlockIf
3255 b.Control = isnonnil
3256 b.Likely = ssa.BranchLikely
3258 bLoad := s.f.NewBlock(ssa.BlockPlain)
3259 bEnd := s.f.NewBlock(ssa.BlockPlain)
3263 bLoad.AddEdgeTo(bEnd)
3266 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3267 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3271 typ := s.variable(&typVar, byteptr)
3272 delete(s.vars, &typVar)
3276 // dottype generates SSA for a type assertion node.
3277 // commaok indicates whether to panic or return a bool.
3278 // If commaok is false, resok will be nil.
3279 func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3280 iface := s.expr(n.Left)
3281 typ := s.ifaceType(n.Left, iface) // actual concrete type
3282 target := s.expr(typename(n.Type)) // target type
3283 if !isdirectiface(n.Type) {
3284 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3285 Fatalf("dottype needs a direct iface type %s", n.Type)
3288 if Debug_typeassert > 0 {
3289 Warnl(int(n.Lineno), "type assertion inlined")
3292 // TODO: If we have a nonempty interface and its itab field is nil,
3293 // then this test is redundant and ifaceType should just branch directly to bFail.
3294 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3296 b.Kind = ssa.BlockIf
3298 b.Likely = ssa.BranchLikely
3300 byteptr := Ptrto(Types[TUINT8])
3302 bOk := s.f.NewBlock(ssa.BlockPlain)
3303 bFail := s.f.NewBlock(ssa.BlockPlain)
3308 // on failure, panic by calling panicdottype
3310 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
3311 s.rtcall(panicdottype, false, nil, typ, target, taddr)
3313 // on success, return idata field
3315 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3318 // commaok is the more complicated case because we have
3319 // a control flow merge point.
3320 bEnd := s.f.NewBlock(ssa.BlockPlain)
3322 // type assertion succeeded
3324 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3325 s.vars[&okVar] = s.constBool(true)
3329 // type assertion failed
3331 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3332 s.vars[&okVar] = s.constBool(false)
3334 bFail.AddEdgeTo(bEnd)
3338 res = s.variable(&idataVar, byteptr)
3339 resok = s.variable(&okVar, Types[TBOOL])
3340 delete(s.vars, &idataVar)
3341 delete(s.vars, &okVar)
3345 // checkgoto checks that a goto from from to to does not
3346 // jump into a block or jump over variable declarations.
3347 // It is a copy of checkgoto in the pre-SSA backend,
3348 // modified only for line number handling.
3349 // TODO: document how this works and why it is designed the way it is.
3350 func (s *state) checkgoto(from *Node, to *Node) {
3351 if from.Sym == to.Sym {
3356 for fs := from.Sym; fs != nil; fs = fs.Link {
3360 for fs := to.Sym; fs != nil; fs = fs.Link {
3364 for ; nf > nt; nf-- {
3368 // decide what to complain about.
3369 // prefer to complain about 'into block' over declarations,
3370 // so scan backward to find most recent block or else dcl.
3375 for ; nt > nf; nt-- {
3394 lno := int(from.Left.Lineno)
3396 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
3398 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
3403 // variable returns the value of a variable at the current location.
3404 func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
3407 v = s.newValue0A(ssa.OpFwdRef, t, name)
3408 s.fwdRefs = append(s.fwdRefs, v)
3410 s.addNamedValue(name, v)
3415 func (s *state) mem() *ssa.Value {
3416 return s.variable(&memVar, ssa.TypeMem)
3419 func (s *state) linkForwardReferences() {
3420 // Build SSA graph. Each variable on its first use in a basic block
3421 // leaves a FwdRef in that block representing the incoming value
3422 // of that variable. This function links that ref up with possible definitions,
3423 // inserting Phi values as needed. This is essentially the algorithm
3424 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3425 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3427 // - We use FwdRef nodes to postpone phi building until the CFG is
3428 // completely built. That way we can avoid the notion of "sealed"
3430 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3431 for len(s.fwdRefs) > 0 {
3432 v := s.fwdRefs[len(s.fwdRefs)-1]
3433 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3438 // resolveFwdRef modifies v to be the variable's value at the start of its block.
3439 // v must be a FwdRef op.
3440 func (s *state) resolveFwdRef(v *ssa.Value) {
3442 name := v.Aux.(*Node)
3445 // Live variable at start of function.
3451 // Not SSAable. Load it.
3452 addr := s.decladdrs[name]
3454 // TODO: closure args reach here.
3455 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
3457 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3458 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3461 v.AddArgs(addr, s.startmem)
3464 if len(b.Preds) == 0 {
3465 // This block is dead; we have no predecessors and we're not the entry block.
3466 // It doesn't matter what we use here as long as it is well-formed.
3467 v.Op = ssa.OpUnknown
3470 // Find variable value on each predecessor.
3471 var argstore [4]*ssa.Value
3472 args := argstore[:0]
3473 for _, p := range b.Preds {
3474 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
3477 // Decide if we need a phi or not. We need a phi if there
3478 // are two different args (which are both not v).
3480 for _, a := range args {
3482 continue // self-reference
3485 continue // already have this witness
3488 // two witnesses, need a phi value
3493 w = a // save witness
3496 s.Fatalf("no witness for reachable phi %s", v)
3498 // One witness. Make v a copy of w.
3503 // lookupVarOutgoing finds the variable's value at the end of block b.
3504 func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
3505 m := s.defvars[b.ID]
3506 if v, ok := m[name]; ok {
3509 // The variable is not defined by b and we haven't
3510 // looked it up yet. Generate a FwdRef for the variable and return that.
3511 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3512 s.fwdRefs = append(s.fwdRefs, v)
3514 s.addNamedValue(name, v)
3518 func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3519 if n.Class == Pxxx {
3520 // Don't track our dummy nodes (&memVar etc.).
3523 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3524 // Don't track autotmp_ variables.
3527 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3528 // TODO: can't handle auto compound objects with pointers yet.
3529 // The live variable analysis barfs because we don't put VARDEF
3530 // pseudos in the right place when we spill to these nodes.
3533 if n.Class == PAUTO && n.Xoffset != 0 {
3534 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3536 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3537 values, ok := s.f.NamedValues[loc]
3539 s.f.Names = append(s.f.Names, loc)
3541 s.f.NamedValues[loc] = append(values, v)
3544 // an unresolved branch
3545 type branch struct {
3546 p *obj.Prog // branch instruction
3547 b *ssa.Block // target
3550 type genState struct {
3551 // branches remembers all the branch instructions we've seen
3552 // and where they would like to go.
3555 // bstart remembers where each block starts (indexed by block ID)
3558 // deferBranches remembers all the defer branches we've seen.
3559 deferBranches []*obj.Prog
3561 // deferTarget remembers the (last) deferreturn call site.
3562 deferTarget *obj.Prog
3565 // genssa appends entries to ptxt for each instruction in f.
3566 // gcargs and gclocals are filled in with pointer maps for the frame.
3567 func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
3570 e := f.Config.Frontend().(*ssaExport)
3571 // We're about to emit a bunch of Progs.
3572 // Since the only way to get here is to explicitly request it,
3573 // just fail on unimplemented instead of trying to unwind our mess.
3574 e.mustImplement = true
3576 // Remember where each block starts.
3577 s.bstart = make([]*obj.Prog, f.NumBlocks())
3579 var valueProgs map[*obj.Prog]*ssa.Value
3580 var blockProgs map[*obj.Prog]*ssa.Block
3581 const logProgs = true
3583 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3584 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3585 f.Logf("genssa %s\n", f.Name)
3586 blockProgs[Pc] = f.Blocks[0]
3589 // Emit basic blocks
3590 for i, b := range f.Blocks {
3592 // Emit values in block
3594 for _, v := range b.Values {
3598 for ; x != Pc; x = x.Link {
3603 // Emit control flow instructions for block
3605 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
3606 // If -N, leave next==nil so every block with successors
3607 // ends in a JMP (except call blocks - plive doesn't like
3608 // select{send,recv} followed by a JMP call). Helps keep
3609 // line numbers for otherwise empty blocks.
3610 next = f.Blocks[i+1]
3615 for ; x != Pc; x = x.Link {
3622 for _, br := range s.branches {
3623 br.p.To.Val = s.bstart[br.b.ID]
3625 if s.deferBranches != nil && s.deferTarget == nil {
3626 // This can happen when the function has a defer but
3627 // no return (because it has an infinite loop).
3631 for _, p := range s.deferBranches {
3632 p.To.Val = s.deferTarget
3636 for p := ptxt; p != nil; p = p.Link {
3638 if v, ok := valueProgs[p]; ok {
3640 } else if b, ok := blockProgs[p]; ok {
3643 s = " " // most value and branch strings are 2-3 characters long
3645 f.Logf("%s\t%s\n", s, p)
3647 if f.Config.HTML != nil {
3648 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3649 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3650 var buf bytes.Buffer
3651 buf.WriteString("<code>")
3652 buf.WriteString("<dl class=\"ssa-gen\">")
3653 for p := ptxt; p != nil; p = p.Link {
3654 buf.WriteString("<dt class=\"ssa-prog-src\">")
3655 if v, ok := valueProgs[p]; ok {
3656 buf.WriteString(v.HTML())
3657 } else if b, ok := blockProgs[p]; ok {
3658 buf.WriteString(b.HTML())
3660 buf.WriteString("</dt>")
3661 buf.WriteString("<dd class=\"ssa-prog\">")
3662 buf.WriteString(html.EscapeString(p.String()))
3663 buf.WriteString("</dd>")
3664 buf.WriteString("</li>")
3666 buf.WriteString("</dl>")
3667 buf.WriteString("</code>")
3668 f.Config.HTML.WriteColumn("genssa", buf.String())
3669 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3674 if f.StaticData != nil {
3675 for _, n := range f.StaticData.([]*Node) {
3676 if !gen_as_init(n, false) {
3677 Fatalf("non-static data marked as static: %v\n\n", n, f)
3682 // Allocate stack frame
3685 // Generate gc bitmaps.
3686 liveness(Curfn, ptxt, gcargs, gclocals)
3690 // Add frame prologue. Zero ambiguously live variables.
3691 Thearch.Defframe(ptxt)
3692 if Debug['f'] != 0 {
3696 // Remove leftover instrumentation from the instruction stream.
3699 f.Config.HTML.Close()
3702 // opregreg emits instructions for
3703 // dest := dest(To) op src(From)
3704 // and also returns the created obj.Prog so it
3705 // may be further adjusted (offset, scale, etc).
3706 func opregreg(op int, dest, src int16) *obj.Prog {
3708 p.From.Type = obj.TYPE_REG
3709 p.To.Type = obj.TYPE_REG
3715 func (s *genState) genValue(v *ssa.Value) {
3718 case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL, ssa.OpAMD64ADDW:
3720 r1 := regnum(v.Args[0])
3721 r2 := regnum(v.Args[1])
3724 p := Prog(v.Op.Asm())
3725 p.From.Type = obj.TYPE_REG
3727 p.To.Type = obj.TYPE_REG
3730 p := Prog(v.Op.Asm())
3731 p.From.Type = obj.TYPE_REG
3733 p.To.Type = obj.TYPE_REG
3738 case ssa.OpAMD64ADDQ:
3740 case ssa.OpAMD64ADDL:
3742 case ssa.OpAMD64ADDW:
3746 p.From.Type = obj.TYPE_MEM
3750 p.To.Type = obj.TYPE_REG
3753 // 2-address opcode arithmetic, symmetric
3754 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
3755 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
3756 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3757 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
3758 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
3759 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
3761 x := regnum(v.Args[0])
3762 y := regnum(v.Args[1])
3763 if x != r && y != r {
3764 opregreg(moveByType(v.Type), r, x)
3767 p := Prog(v.Op.Asm())
3768 p.From.Type = obj.TYPE_REG
3769 p.To.Type = obj.TYPE_REG
3776 // 2-address opcode arithmetic, not symmetric
3777 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
3779 x := regnum(v.Args[0])
3780 y := regnum(v.Args[1])
3783 // compute -(y-x) instead
3788 opregreg(moveByType(v.Type), r, x)
3790 opregreg(v.Op.Asm(), r, y)
3793 p := Prog(x86.ANEGQ) // TODO: use correct size? This is mostly a hack until regalloc does 2-address correctly
3794 p.To.Type = obj.TYPE_REG
3797 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3799 x := regnum(v.Args[0])
3800 y := regnum(v.Args[1])
3801 if y == r && x != r {
3802 // r/y := x op r/y, need to preserve x and rewrite to
3803 // r/y := r/y op x15
3804 x15 := int16(x86.REG_X15)
3805 // register move y to x15
3806 // register move x to y
3807 // rename y with x15
3808 opregreg(moveByType(v.Type), x15, y)
3809 opregreg(moveByType(v.Type), r, x)
3812 opregreg(moveByType(v.Type), r, x)
3814 opregreg(v.Op.Asm(), r, y)
3816 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
3817 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3818 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3819 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
3821 // Arg[0] is already in AX as it's the only register we allow
3822 // and AX is the only output
3823 x := regnum(v.Args[1])
3825 // CPU faults upon signed overflow, which occurs when most
3826 // negative int is divided by -1.
3828 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3829 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3830 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
3834 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
3837 // go ahead and sign extend to save doing it later
3840 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
3845 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
3850 c.From.Type = obj.TYPE_REG
3852 c.To.Type = obj.TYPE_CONST
3855 j.To.Type = obj.TYPE_BRANCH
3859 // for unsigned ints, we sign extend by setting DX = 0
3860 // signed ints were sign extended above
3861 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3862 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3863 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
3864 c := Prog(x86.AXORQ)
3865 c.From.Type = obj.TYPE_REG
3866 c.From.Reg = x86.REG_DX
3867 c.To.Type = obj.TYPE_REG
3868 c.To.Reg = x86.REG_DX
3871 p := Prog(v.Op.Asm())
3872 p.From.Type = obj.TYPE_REG
3875 // signed division, rest of the check for -1 case
3877 j2 := Prog(obj.AJMP)
3878 j2.To.Type = obj.TYPE_BRANCH
3881 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3882 v.Op == ssa.OpAMD64DIVW {
3885 n.To.Type = obj.TYPE_REG
3886 n.To.Reg = x86.REG_AX
3890 n.From.Type = obj.TYPE_REG
3891 n.From.Reg = x86.REG_DX
3892 n.To.Type = obj.TYPE_REG
3893 n.To.Reg = x86.REG_DX
3900 case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3901 ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
3902 // the frontend rewrites constant division by 8/16/32 bit integers into
3903 // HMUL by a constant
3904 // SSA rewrites generate the 64 bit versions
3906 // Arg[0] is already in AX as it's the only register we allow
3907 // and DX is the only output we care about (the high bits)
3908 p := Prog(v.Op.Asm())
3909 p.From.Type = obj.TYPE_REG
3910 p.From.Reg = regnum(v.Args[1])
3912 // IMULB puts the high portion in AH instead of DL,
3913 // so move it to DL for consistency
3914 if v.Type.Size() == 1 {
3915 m := Prog(x86.AMOVB)
3916 m.From.Type = obj.TYPE_REG
3917 m.From.Reg = x86.REG_AH
3918 m.To.Type = obj.TYPE_REG
3919 m.To.Reg = x86.REG_DX
3922 case ssa.OpAMD64AVGQU:
3923 // compute (x+y)/2 unsigned.
3924 // Do a 64-bit add, the overflow goes into the carry.
3925 // Shift right once and pull the carry back into the 63rd bit.
3927 x := regnum(v.Args[0])
3928 y := regnum(v.Args[1])
3929 if x != r && y != r {
3930 opregreg(moveByType(v.Type), r, x)
3933 p := Prog(x86.AADDQ)
3934 p.From.Type = obj.TYPE_REG
3935 p.To.Type = obj.TYPE_REG
3943 p.From.Type = obj.TYPE_CONST
3945 p.To.Type = obj.TYPE_REG
3948 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
3949 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
3950 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
3951 x := regnum(v.Args[0])
3954 if r == x86.REG_CX {
3955 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
3957 p := Prog(moveByType(v.Type))
3958 p.From.Type = obj.TYPE_REG
3960 p.To.Type = obj.TYPE_REG
3963 p := Prog(v.Op.Asm())
3964 p.From.Type = obj.TYPE_REG
3965 p.From.Reg = regnum(v.Args[1]) // should be CX
3966 p.To.Type = obj.TYPE_REG
3968 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
3970 a := regnum(v.Args[0])
3972 if v.AuxInt2Int64() == 1 {
3975 // Software optimization manual recommends add $1,reg.
3976 // But inc/dec is 1 byte smaller. ICC always uses inc
3977 // Clang/GCC choose depending on flags, but prefer add.
3978 // Experiments show that inc/dec is both a little faster
3979 // and make a binary a little smaller.
3980 case ssa.OpAMD64ADDQconst:
3982 case ssa.OpAMD64ADDLconst:
3984 case ssa.OpAMD64ADDWconst:
3988 p.To.Type = obj.TYPE_REG
3991 } else if v.AuxInt2Int64() == -1 {
3994 case ssa.OpAMD64ADDQconst:
3996 case ssa.OpAMD64ADDLconst:
3998 case ssa.OpAMD64ADDWconst:
4002 p.To.Type = obj.TYPE_REG
4006 p := Prog(v.Op.Asm())
4007 p.From.Type = obj.TYPE_CONST
4008 p.From.Offset = v.AuxInt2Int64()
4009 p.To.Type = obj.TYPE_REG
4016 case ssa.OpAMD64ADDQconst:
4018 case ssa.OpAMD64ADDLconst:
4020 case ssa.OpAMD64ADDWconst:
4024 p.From.Type = obj.TYPE_MEM
4026 p.From.Offset = v.AuxInt2Int64()
4027 p.To.Type = obj.TYPE_REG
4029 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
4031 x := regnum(v.Args[0])
4033 p := Prog(moveByType(v.Type))
4034 p.From.Type = obj.TYPE_REG
4036 p.To.Type = obj.TYPE_REG
4039 p := Prog(v.Op.Asm())
4040 p.From.Type = obj.TYPE_CONST
4041 p.From.Offset = v.AuxInt2Int64()
4042 p.To.Type = obj.TYPE_REG
4044 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
4045 // instead of using the MOVQ above.
4046 //p.From3 = new(obj.Addr)
4047 //p.From3.Type = obj.TYPE_REG
4048 //p.From3.Reg = regnum(v.Args[0])
4049 case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst:
4050 x := regnum(v.Args[0])
4052 // We have 3-op add (lea), so transforming a = b - const into
4053 // a = b + (- const), saves us 1 instruction. We can't fit
4054 // - (-1 << 31) into 4 bytes offset in lea.
4055 // We handle 2-address just fine below.
4056 if v.AuxInt2Int64() == -1<<31 || x == r {
4058 // This code compensates for the fact that the register allocator
4059 // doesn't understand 2-address instructions yet. TODO: fix that.
4060 p := Prog(moveByType(v.Type))
4061 p.From.Type = obj.TYPE_REG
4063 p.To.Type = obj.TYPE_REG
4066 p := Prog(v.Op.Asm())
4067 p.From.Type = obj.TYPE_CONST
4068 p.From.Offset = v.AuxInt2Int64()
4069 p.To.Type = obj.TYPE_REG
4071 } else if x == r && v.AuxInt2Int64() == -1 {
4073 // x = x - (-1) is the same as x++
4074 // See OpAMD64ADDQconst comments about inc vs add $1,reg
4076 case ssa.OpAMD64SUBQconst:
4078 case ssa.OpAMD64SUBLconst:
4080 case ssa.OpAMD64SUBWconst:
4084 p.To.Type = obj.TYPE_REG
4086 } else if x == r && v.AuxInt2Int64() == 1 {
4089 case ssa.OpAMD64SUBQconst:
4091 case ssa.OpAMD64SUBLconst:
4093 case ssa.OpAMD64SUBWconst:
4097 p.To.Type = obj.TYPE_REG
4102 case ssa.OpAMD64SUBQconst:
4104 case ssa.OpAMD64SUBLconst:
4106 case ssa.OpAMD64SUBWconst:
4110 p.From.Type = obj.TYPE_MEM
4112 p.From.Offset = -v.AuxInt2Int64()
4113 p.To.Type = obj.TYPE_REG
4117 case ssa.OpAMD64ADDBconst,
4118 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
4119 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
4120 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
4121 ssa.OpAMD64SUBBconst, ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst,
4122 ssa.OpAMD64SHLBconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst,
4123 ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst,
4124 ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst,
4125 ssa.OpAMD64ROLBconst:
4126 // This code compensates for the fact that the register allocator
4127 // doesn't understand 2-address instructions yet. TODO: fix that.
4128 x := regnum(v.Args[0])
4131 p := Prog(moveByType(v.Type))
4132 p.From.Type = obj.TYPE_REG
4134 p.To.Type = obj.TYPE_REG
4137 p := Prog(v.Op.Asm())
4138 p.From.Type = obj.TYPE_CONST
4139 p.From.Offset = v.AuxInt2Int64()
4140 p.To.Type = obj.TYPE_REG
4142 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
4144 p := Prog(v.Op.Asm())
4145 p.From.Type = obj.TYPE_REG
4147 p.To.Type = obj.TYPE_REG
4149 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
4150 p := Prog(x86.ALEAQ)
4151 p.From.Type = obj.TYPE_MEM
4152 p.From.Reg = regnum(v.Args[0])
4154 case ssa.OpAMD64LEAQ1:
4156 case ssa.OpAMD64LEAQ2:
4158 case ssa.OpAMD64LEAQ4:
4160 case ssa.OpAMD64LEAQ8:
4163 p.From.Index = regnum(v.Args[1])
4165 p.To.Type = obj.TYPE_REG
4166 p.To.Reg = regnum(v)
4167 case ssa.OpAMD64LEAQ:
4168 p := Prog(x86.ALEAQ)
4169 p.From.Type = obj.TYPE_MEM
4170 p.From.Reg = regnum(v.Args[0])
4172 p.To.Type = obj.TYPE_REG
4173 p.To.Reg = regnum(v)
4174 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
4175 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
4176 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
4177 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
4178 // Go assembler has swapped operands for UCOMISx relative to CMP,
4179 // must account for that right here.
4180 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
4181 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
4182 p := Prog(v.Op.Asm())
4183 p.From.Type = obj.TYPE_REG
4184 p.From.Reg = regnum(v.Args[0])
4185 p.To.Type = obj.TYPE_CONST
4186 p.To.Offset = v.AuxInt2Int64()
4187 case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
4188 p := Prog(v.Op.Asm())
4189 p.From.Type = obj.TYPE_CONST
4190 p.From.Offset = v.AuxInt2Int64()
4191 p.To.Type = obj.TYPE_REG
4192 p.To.Reg = regnum(v.Args[0])
4193 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
4195 p := Prog(v.Op.Asm())
4196 p.From.Type = obj.TYPE_CONST
4197 p.From.Offset = v.AuxInt2Int64()
4198 p.To.Type = obj.TYPE_REG
4200 // If flags are live at this instruction, suppress the
4201 // MOV $0,AX -> XOR AX,AX optimization.
4203 p.Mark |= x86.PRESERVEFLAGS
4205 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
4207 p := Prog(v.Op.Asm())
4208 p.From.Type = obj.TYPE_FCONST
4209 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
4210 p.To.Type = obj.TYPE_REG
4212 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:
4213 p := Prog(v.Op.Asm())
4214 p.From.Type = obj.TYPE_MEM
4215 p.From.Reg = regnum(v.Args[0])
4217 p.To.Type = obj.TYPE_REG
4218 p.To.Reg = regnum(v)
4219 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
4220 p := Prog(v.Op.Asm())
4221 p.From.Type = obj.TYPE_MEM
4222 p.From.Reg = regnum(v.Args[0])
4225 p.From.Index = regnum(v.Args[1])
4226 p.To.Type = obj.TYPE_REG
4227 p.To.Reg = regnum(v)
4228 case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
4229 p := Prog(v.Op.Asm())
4230 p.From.Type = obj.TYPE_MEM
4231 p.From.Reg = regnum(v.Args[0])
4234 p.From.Index = regnum(v.Args[1])
4235 p.To.Type = obj.TYPE_REG
4236 p.To.Reg = regnum(v)
4237 case ssa.OpAMD64MOVWloadidx2:
4238 p := Prog(v.Op.Asm())
4239 p.From.Type = obj.TYPE_MEM
4240 p.From.Reg = regnum(v.Args[0])
4243 p.From.Index = regnum(v.Args[1])
4244 p.To.Type = obj.TYPE_REG
4245 p.To.Reg = regnum(v)
4246 case ssa.OpAMD64MOVBloadidx1:
4247 p := Prog(v.Op.Asm())
4248 p.From.Type = obj.TYPE_MEM
4249 p.From.Reg = regnum(v.Args[0])
4252 p.From.Index = regnum(v.Args[1])
4253 p.To.Type = obj.TYPE_REG
4254 p.To.Reg = regnum(v)
4255 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
4256 p := Prog(v.Op.Asm())
4257 p.From.Type = obj.TYPE_REG
4258 p.From.Reg = regnum(v.Args[1])
4259 p.To.Type = obj.TYPE_MEM
4260 p.To.Reg = regnum(v.Args[0])
4262 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
4263 p := Prog(v.Op.Asm())
4264 p.From.Type = obj.TYPE_REG
4265 p.From.Reg = regnum(v.Args[2])
4266 p.To.Type = obj.TYPE_MEM
4267 p.To.Reg = regnum(v.Args[0])
4269 p.To.Index = regnum(v.Args[1])
4271 case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
4272 p := Prog(v.Op.Asm())
4273 p.From.Type = obj.TYPE_REG
4274 p.From.Reg = regnum(v.Args[2])
4275 p.To.Type = obj.TYPE_MEM
4276 p.To.Reg = regnum(v.Args[0])
4278 p.To.Index = regnum(v.Args[1])
4280 case ssa.OpAMD64MOVWstoreidx2:
4281 p := Prog(v.Op.Asm())
4282 p.From.Type = obj.TYPE_REG
4283 p.From.Reg = regnum(v.Args[2])
4284 p.To.Type = obj.TYPE_MEM
4285 p.To.Reg = regnum(v.Args[0])
4287 p.To.Index = regnum(v.Args[1])
4289 case ssa.OpAMD64MOVBstoreidx1:
4290 p := Prog(v.Op.Asm())
4291 p.From.Type = obj.TYPE_REG
4292 p.From.Reg = regnum(v.Args[2])
4293 p.To.Type = obj.TYPE_MEM
4294 p.To.Reg = regnum(v.Args[0])
4296 p.To.Index = regnum(v.Args[1])
4298 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4299 p := Prog(v.Op.Asm())
4300 p.From.Type = obj.TYPE_CONST
4301 sc := v.AuxValAndOff()
4304 case ssa.OpAMD64MOVBstoreconst:
4306 case ssa.OpAMD64MOVWstoreconst:
4308 case ssa.OpAMD64MOVLstoreconst:
4310 case ssa.OpAMD64MOVQstoreconst:
4313 p.To.Type = obj.TYPE_MEM
4314 p.To.Reg = regnum(v.Args[0])
4315 addAux2(&p.To, v, sc.Off())
4316 case ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1:
4317 p := Prog(v.Op.Asm())
4318 p.From.Type = obj.TYPE_CONST
4319 sc := v.AuxValAndOff()
4321 case ssa.OpAMD64MOVBstoreconstidx1:
4322 p.From.Offset = int64(int8(sc.Val()))
4324 case ssa.OpAMD64MOVWstoreconstidx2:
4325 p.From.Offset = int64(int16(sc.Val()))
4327 case ssa.OpAMD64MOVLstoreconstidx4:
4328 p.From.Offset = int64(int32(sc.Val()))
4330 case ssa.OpAMD64MOVQstoreconstidx8:
4331 p.From.Offset = sc.Val()
4334 p.To.Type = obj.TYPE_MEM
4335 p.To.Reg = regnum(v.Args[0])
4336 p.To.Index = regnum(v.Args[1])
4337 addAux2(&p.To, v, sc.Off())
4338 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
4339 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
4340 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
4341 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
4342 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
4343 case ssa.OpAMD64DUFFZERO:
4344 p := Prog(obj.ADUFFZERO)
4345 p.To.Type = obj.TYPE_ADDR
4346 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
4347 p.To.Offset = v.AuxInt
4348 case ssa.OpAMD64MOVOconst:
4350 v.Unimplementedf("MOVOconst can only do constant=0")
4353 opregreg(x86.AXORPS, r, r)
4354 case ssa.OpAMD64DUFFCOPY:
4355 p := Prog(obj.ADUFFCOPY)
4356 p.To.Type = obj.TYPE_ADDR
4357 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
4358 p.To.Offset = v.AuxInt
4360 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
4361 if v.Type.IsMemory() {
4364 x := regnum(v.Args[0])
4367 opregreg(moveByType(v.Type), y, x)
4370 if v.Type.IsFlags() {
4371 v.Unimplementedf("load flags not implemented: %v", v.LongString())
4374 p := Prog(loadByType(v.Type))
4375 n, off := autoVar(v.Args[0])
4376 p.From.Type = obj.TYPE_MEM
4378 p.From.Sym = Linksym(n.Sym)
4380 if n.Class == PPARAM {
4381 p.From.Name = obj.NAME_PARAM
4382 p.From.Offset += n.Xoffset
4384 p.From.Name = obj.NAME_AUTO
4386 p.To.Type = obj.TYPE_REG
4387 p.To.Reg = regnum(v)
4389 case ssa.OpStoreReg:
4390 if v.Type.IsFlags() {
4391 v.Unimplementedf("store flags not implemented: %v", v.LongString())
4394 p := Prog(storeByType(v.Type))
4395 p.From.Type = obj.TYPE_REG
4396 p.From.Reg = regnum(v.Args[0])
4397 n, off := autoVar(v)
4398 p.To.Type = obj.TYPE_MEM
4400 p.To.Sym = Linksym(n.Sym)
4402 if n.Class == PPARAM {
4403 p.To.Name = obj.NAME_PARAM
4404 p.To.Offset += n.Xoffset
4406 p.To.Name = obj.NAME_AUTO
4409 // just check to make sure regalloc and stackalloc did it right
4410 if v.Type.IsMemory() {
4414 loc := f.RegAlloc[v.ID]
4415 for _, a := range v.Args {
4416 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
4417 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)
4421 // memory arg needs no code
4423 // input args need no code
4424 case ssa.OpAMD64LoweredGetClosurePtr:
4425 // Output is hardwired to DX only,
4426 // and DX contains the closure pointer on
4427 // closure entry, and this "instruction"
4428 // is scheduled to the very beginning
4429 // of the entry block.
4430 case ssa.OpAMD64LoweredGetG:
4432 // See the comments in cmd/internal/obj/x86/obj6.go
4433 // near CanUse1InsnTLS for a detailed explanation of these instructions.
4434 if x86.CanUse1InsnTLS(Ctxt) {
4436 p := Prog(x86.AMOVQ)
4437 p.From.Type = obj.TYPE_MEM
4438 p.From.Reg = x86.REG_TLS
4439 p.To.Type = obj.TYPE_REG
4443 // MOVQ (r)(TLS*1), r
4444 p := Prog(x86.AMOVQ)
4445 p.From.Type = obj.TYPE_REG
4446 p.From.Reg = x86.REG_TLS
4447 p.To.Type = obj.TYPE_REG
4449 q := Prog(x86.AMOVQ)
4450 q.From.Type = obj.TYPE_MEM
4452 q.From.Index = x86.REG_TLS
4454 q.To.Type = obj.TYPE_REG
4457 case ssa.OpAMD64CALLstatic:
4458 p := Prog(obj.ACALL)
4459 p.To.Type = obj.TYPE_MEM
4460 p.To.Name = obj.NAME_EXTERN
4461 p.To.Sym = Linksym(v.Aux.(*Sym))
4462 if Maxarg < v.AuxInt {
4465 case ssa.OpAMD64CALLclosure:
4466 p := Prog(obj.ACALL)
4467 p.To.Type = obj.TYPE_REG
4468 p.To.Reg = regnum(v.Args[0])
4469 if Maxarg < v.AuxInt {
4472 case ssa.OpAMD64CALLdefer:
4473 p := Prog(obj.ACALL)
4474 p.To.Type = obj.TYPE_MEM
4475 p.To.Name = obj.NAME_EXTERN
4476 p.To.Sym = Linksym(Deferproc.Sym)
4477 if Maxarg < v.AuxInt {
4480 // defer returns in rax:
4481 // 0 if we should continue executing
4482 // 1 if we should jump to deferreturn call
4483 p = Prog(x86.ATESTL)
4484 p.From.Type = obj.TYPE_REG
4485 p.From.Reg = x86.REG_AX
4486 p.To.Type = obj.TYPE_REG
4487 p.To.Reg = x86.REG_AX
4489 p.To.Type = obj.TYPE_BRANCH
4490 s.deferBranches = append(s.deferBranches, p)
4491 case ssa.OpAMD64CALLgo:
4492 p := Prog(obj.ACALL)
4493 p.To.Type = obj.TYPE_MEM
4494 p.To.Name = obj.NAME_EXTERN
4495 p.To.Sym = Linksym(Newproc.Sym)
4496 if Maxarg < v.AuxInt {
4499 case ssa.OpAMD64CALLinter:
4500 p := Prog(obj.ACALL)
4501 p.To.Type = obj.TYPE_REG
4502 p.To.Reg = regnum(v.Args[0])
4503 if Maxarg < v.AuxInt {
4506 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4507 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
4508 x := regnum(v.Args[0])
4511 p := Prog(moveByType(v.Type))
4512 p.From.Type = obj.TYPE_REG
4514 p.To.Type = obj.TYPE_REG
4517 p := Prog(v.Op.Asm())
4518 p.To.Type = obj.TYPE_REG
4520 case ssa.OpAMD64SQRTSD:
4521 p := Prog(v.Op.Asm())
4522 p.From.Type = obj.TYPE_REG
4523 p.From.Reg = regnum(v.Args[0])
4524 p.To.Type = obj.TYPE_REG
4525 p.To.Reg = regnum(v)
4526 case ssa.OpSP, ssa.OpSB:
4528 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4529 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4530 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
4531 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
4532 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
4533 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
4534 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
4535 p := Prog(v.Op.Asm())
4536 p.To.Type = obj.TYPE_REG
4537 p.To.Reg = regnum(v)
4539 case ssa.OpAMD64SETNEF:
4540 p := Prog(v.Op.Asm())
4541 p.To.Type = obj.TYPE_REG
4542 p.To.Reg = regnum(v)
4543 q := Prog(x86.ASETPS)
4544 q.To.Type = obj.TYPE_REG
4545 q.To.Reg = x86.REG_AX
4546 // TODO AORQ copied from old code generator, why not AORB?
4547 opregreg(x86.AORQ, regnum(v), x86.REG_AX)
4549 case ssa.OpAMD64SETEQF:
4550 p := Prog(v.Op.Asm())
4551 p.To.Type = obj.TYPE_REG
4552 p.To.Reg = regnum(v)
4553 q := Prog(x86.ASETPC)
4554 q.To.Type = obj.TYPE_REG
4555 q.To.Reg = x86.REG_AX
4556 // TODO AANDQ copied from old code generator, why not AANDB?
4557 opregreg(x86.AANDQ, regnum(v), x86.REG_AX)
4559 case ssa.OpAMD64InvertFlags:
4560 v.Fatalf("InvertFlags should never make it to codegen %v", v)
4561 case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
4562 v.Fatalf("Flag* ops should never make it to codegen %v", v)
4563 case ssa.OpAMD64REPSTOSQ:
4566 case ssa.OpAMD64REPMOVSQ:
4570 Gvardef(v.Aux.(*Node))
4572 gvarkill(v.Aux.(*Node))
4574 gvarlive(v.Aux.(*Node))
4575 case ssa.OpAMD64LoweredNilCheck:
4576 // Optimization - if the subsequent block has a load or store
4577 // at the same address, we don't need to issue this instruction.
4579 for _, w := range v.Block.Succs[0].Values {
4580 if w.Op == ssa.OpPhi {
4581 if w.Type.IsMemory() {
4586 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4587 // w doesn't use a store - can't be a memory op.
4590 if w.Args[len(w.Args)-1] != mem {
4591 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4594 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
4595 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
4596 ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload,
4597 ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload,
4598 ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVOload,
4599 ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVOstore:
4600 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
4601 if Debug_checknil != 0 && int(v.Line) > 1 {
4602 Warnl(int(v.Line), "removed nil check")
4606 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4607 off := ssa.ValAndOff(v.AuxInt).Off()
4608 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
4609 if Debug_checknil != 0 && int(v.Line) > 1 {
4610 Warnl(int(v.Line), "removed nil check")
4615 if w.Type.IsMemory() {
4616 if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
4621 // We can't delay the nil check past the next store.
4625 // Issue a load which will fault if the input is nil.
4626 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4627 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4628 // but it doesn't have false dependency on AX.
4629 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4630 // That trades clobbering flags for clobbering a register.
4631 p := Prog(x86.ATESTB)
4632 p.From.Type = obj.TYPE_REG
4633 p.From.Reg = x86.REG_AX
4634 p.To.Type = obj.TYPE_MEM
4635 p.To.Reg = regnum(v.Args[0])
4637 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
4638 Warnl(int(v.Line), "generated nil check")
4641 v.Unimplementedf("genValue not implemented: %s", v.LongString())
4645 // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
4646 func (s *genState) markMoves(b *ssa.Block) {
4647 flive := b.FlagsLiveAtEnd
4648 if b.Control != nil && b.Control.Type.IsFlags() {
4651 for i := len(b.Values) - 1; i >= 0; i-- {
4653 if flive && (v.Op == ssa.OpAMD64MOVBconst || v.Op == ssa.OpAMD64MOVWconst || v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
4654 // The "mark" is any non-nil Aux value.
4657 if v.Type.IsFlags() {
4660 for _, a := range v.Args {
4661 if a.Type.IsFlags() {
4668 // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4669 func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4671 // TODO: use zero register on archs that support it.
4672 p.From.Type = obj.TYPE_CONST
4674 p.To.Type = obj.TYPE_MEM
4676 p.To.Offset = offset
4678 nleft = nbytes - width
4679 return nleft, offset
4682 var blockJump = [...]struct {
4685 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4686 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4687 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4688 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4689 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4690 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4691 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4692 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4693 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4694 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
4695 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4696 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4699 type floatingEQNEJump struct {
4703 var eqfJumps = [2][2]floatingEQNEJump{
4704 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4705 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4707 var nefJumps = [2][2]floatingEQNEJump{
4708 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4709 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4712 func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4713 p := Prog(jumps.jump)
4714 p.To.Type = obj.TYPE_BRANCH
4716 branches = append(branches, branch{p, b.Succs[to]})
4720 // liblink reorders the instruction stream as it sees fit.
4721 // Pass along what we know so liblink can make use of it.
4722 // TODO: Once we've fully switched to SSA,
4723 // make liblink leave our output alone.
4725 case ssa.BranchUnlikely:
4726 p.From.Type = obj.TYPE_CONST
4728 case ssa.BranchLikely:
4729 p.From.Type = obj.TYPE_CONST
4735 func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
4739 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4740 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
4742 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4743 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4745 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4746 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
4748 q.To.Type = obj.TYPE_BRANCH
4749 s.branches = append(s.branches, branch{q, b.Succs[1]})
4753 func (s *genState) genBlock(b, next *ssa.Block) {
4757 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
4758 if b.Succs[0] != next {
4760 p.To.Type = obj.TYPE_BRANCH
4761 s.branches = append(s.branches, branch{p, b.Succs[0]})
4764 Prog(obj.AUNDEF) // tell plive.go that we never reach here
4770 case ssa.BlockRetJmp:
4772 p.To.Type = obj.TYPE_MEM
4773 p.To.Name = obj.NAME_EXTERN
4774 p.To.Sym = Linksym(b.Aux.(*Sym))
4776 case ssa.BlockAMD64EQF:
4777 genFPJump(s, b, next, &eqfJumps)
4779 case ssa.BlockAMD64NEF:
4780 genFPJump(s, b, next, &nefJumps)
4782 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4783 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4784 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4785 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4786 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
4787 jmp := blockJump[b.Kind]
4792 p = Prog(jmp.invasm)
4794 p.To.Type = obj.TYPE_BRANCH
4795 s.branches = append(s.branches, branch{p, b.Succs[1]})
4798 p.To.Type = obj.TYPE_BRANCH
4799 s.branches = append(s.branches, branch{p, b.Succs[0]})
4802 p.To.Type = obj.TYPE_BRANCH
4803 s.branches = append(s.branches, branch{p, b.Succs[0]})
4805 q.To.Type = obj.TYPE_BRANCH
4806 s.branches = append(s.branches, branch{q, b.Succs[1]})
4809 // liblink reorders the instruction stream as it sees fit.
4810 // Pass along what we know so liblink can make use of it.
4811 // TODO: Once we've fully switched to SSA,
4812 // make liblink leave our output alone.
4814 case ssa.BranchUnlikely:
4815 p.From.Type = obj.TYPE_CONST
4817 case ssa.BranchLikely:
4818 p.From.Type = obj.TYPE_CONST
4823 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
4827 func (s *genState) deferReturn() {
4828 // Deferred calls will appear to be returning to
4829 // the CALL deferreturn(SB) that we are about to emit.
4830 // However, the stack trace code will show the line
4831 // of the instruction byte before the return PC.
4832 // To avoid that being an unrelated instruction,
4833 // insert an actual hardware NOP that will have the right line number.
4834 // This is different from obj.ANOP, which is a virtual no-op
4835 // that doesn't make it into the instruction stream.
4838 p := Prog(obj.ACALL)
4839 p.To.Type = obj.TYPE_MEM
4840 p.To.Name = obj.NAME_EXTERN
4841 p.To.Sym = Linksym(Deferreturn.Sym)
4844 // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4845 func addAux(a *obj.Addr, v *ssa.Value) {
4846 addAux2(a, v, v.AuxInt)
4848 func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
4849 if a.Type != obj.TYPE_MEM {
4850 v.Fatalf("bad addAux addr %s", a)
4852 // add integer offset
4855 // If no additional symbol offset, we're done.
4859 // Add symbol's offset from its base register.
4860 switch sym := v.Aux.(type) {
4861 case *ssa.ExternSymbol:
4862 a.Name = obj.NAME_EXTERN
4863 a.Sym = Linksym(sym.Sym.(*Sym))
4864 case *ssa.ArgSymbol:
4865 n := sym.Node.(*Node)
4866 a.Name = obj.NAME_PARAM
4868 a.Sym = Linksym(n.Orig.Sym)
4869 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
4870 case *ssa.AutoSymbol:
4871 n := sym.Node.(*Node)
4872 a.Name = obj.NAME_AUTO
4874 a.Sym = Linksym(n.Sym)
4876 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4880 // extendIndex extends v to a full int width.
4881 func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4882 size := v.Type.Size()
4883 if size == s.config.IntSize {
4886 if size > s.config.IntSize {
4887 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
4888 // the high word and branch to out-of-bounds failure if it is not 0.
4889 s.Unimplementedf("64->32 index truncation not implemented")
4893 // Extend value to the required size
4895 if v.Type.IsSigned() {
4896 switch 10*size + s.config.IntSize {
4898 op = ssa.OpSignExt8to32
4900 op = ssa.OpSignExt8to64
4902 op = ssa.OpSignExt16to32
4904 op = ssa.OpSignExt16to64
4906 op = ssa.OpSignExt32to64
4908 s.Fatalf("bad signed index extension %s", v.Type)
4911 switch 10*size + s.config.IntSize {
4913 op = ssa.OpZeroExt8to32
4915 op = ssa.OpZeroExt8to64
4917 op = ssa.OpZeroExt16to32
4919 op = ssa.OpZeroExt16to64
4921 op = ssa.OpZeroExt32to64
4923 s.Fatalf("bad unsigned index extension %s", v.Type)
4926 return s.newValue1(op, Types[TINT], v)
4929 // ssaRegToReg maps ssa register numbers to obj register numbers.
4930 var ssaRegToReg = [...]int16{
4963 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
4964 // TODO: arch-dependent
4967 // loadByType returns the load instruction of the given type.
4968 func loadByType(t ssa.Type) int {
4969 // For x86, there's no difference between load and store opcodes.
4970 return storeByType(t)
4973 // storeByType returns the store instruction of the given type.
4974 func storeByType(t ssa.Type) int {
4995 panic("bad store type")
4998 // moveByType returns the reg->reg move instruction of the given type.
4999 func moveByType(t ssa.Type) int {
5001 // Moving the whole sse2 register is faster
5002 // than moving just the correct low portion of it.
5015 panic("bad int register width")
5018 panic("bad register type")
5021 // regnum returns the register (in cmd/internal/obj numbering) to
5022 // which v has been allocated. Panics if v is not assigned to a
5024 // TODO: Make this panic again once it stops happening routinely.
5025 func regnum(v *ssa.Value) int16 {
5026 reg := v.Block.Func.RegAlloc[v.ID]
5028 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
5031 return ssaRegToReg[reg.(*ssa.Register).Num]
5034 // autoVar returns a *Node and int64 representing the auto variable and offset within it
5035 // where v should be spilled.
5036 func autoVar(v *ssa.Value) (*Node, int64) {
5037 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
5038 if v.Type.Size() > loc.Type.Size() {
5039 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
5041 return loc.N.(*Node), loc.Off
5044 // fieldIdx finds the index of the field referred to by the ODOT node n.
5045 func fieldIdx(n *Node) int64 {
5048 if t.Etype != TSTRUCT {
5049 panic("ODOT's LHS is not a struct")
5053 for t1 := t.Type; t1 != nil; t1 = t1.Down {
5054 if t1.Etype != TFIELD {
5055 panic("non-TFIELD in TSTRUCT")
5057 if t1.Sym != f.Sym {
5061 if t1.Width != n.Xoffset {
5062 panic("field offset doesn't match")
5066 panic(fmt.Sprintf("can't find field in expr %s\n", n))
5068 // TODO: keep the result of this fucntion somewhere in the ODOT Node
5069 // so we don't have to recompute it each time we need it.
5072 // ssaExport exports a bunch of compiler services for the ssa backend.
5073 type ssaExport struct {
5079 func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
5080 func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
5081 func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
5082 func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
5083 func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
5084 func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
5085 func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
5086 func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
5087 func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
5088 func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
5089 func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
5090 func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
5091 func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
5092 func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
5093 func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
5095 // StringData returns a symbol (a *Sym wrapped in an interface) which
5096 // is the data component of a global string constant containing s.
5097 func (*ssaExport) StringData(s string) interface{} {
5098 // TODO: is idealstring correct? It might not matter...
5099 _, data := stringsym(s)
5100 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
5103 func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
5104 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
5105 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
5109 func (e *ssaExport) CanSSA(t ssa.Type) bool {
5110 return canSSAType(t.(*Type))
5113 func (e *ssaExport) Line(line int32) string {
5114 return Ctxt.Line(int(line))
5117 // Log logs a message from the compiler.
5118 func (e *ssaExport) Logf(msg string, args ...interface{}) {
5119 // If e was marked as unimplemented, anything could happen. Ignore.
5120 if e.log && !e.unimplemented {
5121 fmt.Printf(msg, args...)
5125 func (e *ssaExport) Log() bool {
5129 // Fatal reports a compiler error and exits.
5130 func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
5131 // If e was marked as unimplemented, anything could happen. Ignore.
5132 if !e.unimplemented {
5134 Fatalf(msg, args...)
5138 // Unimplemented reports that the function cannot be compiled.
5139 // It will be removed once SSA work is complete.
5140 func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
5141 if e.mustImplement {
5143 Fatalf(msg, args...)
5145 const alwaysLog = false // enable to calculate top unimplemented features
5146 if !e.unimplemented && (e.log || alwaysLog) {
5147 // first implementation failure, print explanation
5148 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
5150 e.unimplemented = true
5153 // Warnl reports a "warning", which is usually flag-triggered
5154 // logging output for the benefit of tests.
5155 func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
5156 Warnl(line, fmt_, args...)
5159 func (e *ssaExport) Debug_checknil() bool {
5160 return Debug_checknil != 0
5163 func (n *Node) Typ() ssa.Type {