blob: f83b88d79e0813fb09a4797f2a03ddc9df2a9a39 [file] [log] [blame]
Keith Randalld2fd43a2015-04-15 15:51:25 -07001// 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.
4
5package gc
6
7import (
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07008 "bytes"
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07009 "fmt"
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -070010 "html"
Todd Neal19447a62015-09-04 06:33:56 -050011 "math"
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -070012 "os"
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -060013 "strings"
Keith Randalld2fd43a2015-04-15 15:51:25 -070014
Keith Randall067e8df2015-05-28 13:49:20 -070015 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070016 "cmd/internal/obj"
Keith Randall8c46aa52015-06-19 21:02:28 -070017 "cmd/internal/obj/x86"
Keith Randalld2fd43a2015-04-15 15:51:25 -070018)
19
Keith Randall31115a52015-10-23 19:12:49 -070020// Smallest possible faulting page at address zero.
21const minZeroPage = 4096
22
Keith Randall2f57d0f2016-01-28 13:46:30 -080023var ssaConfig *ssa.Config
24var ssaExp ssaExport
25
David Chase378a8632016-02-25 13:10:51 -050026func initssa() *ssa.Config {
27 ssaExp.unimplemented = false
28 ssaExp.mustImplement = true
29 if ssaConfig == nil {
30 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
31 }
32 return ssaConfig
33}
34
Keith Randall5b355a72015-12-11 20:41:52 -080035func shouldssa(fn *Node) bool {
36 if Thearch.Thestring != "amd64" {
37 return false
38 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070039
David Chasee99dd522015-10-19 11:36:07 -040040 // 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
43
David Chase729abfa2015-10-26 17:34:06 -040044 // 2. IF GOSSAHASH == "" THEN
David Chasee99dd522015-10-19 11:36:07 -040045 // compile this function (and everything else) with SSA
46
David Chase729abfa2015-10-26 17:34:06 -040047 // 3. IF GOSSAHASH == "n" or "N"
David Chasee99dd522015-10-19 11:36:07 -040048 // IF GOSSAPKG == current package name THEN
49 // compile this function (and everything in this package) with SSA
50 // ELSE
51 // use the old back end for this function.
52 // This is for compatibility with existing test harness and should go away.
53
54 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
55 // compile this function with SSA
56 // ELSE
57 // compile this function with the old back end.
58
David Chase729abfa2015-10-26 17:34:06 -040059 // 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
62 // 0 and 1.
David Chasee99dd522015-10-19 11:36:07 -040063
Keith Randall5b355a72015-12-11 20:41:52 -080064 name := fn.Func.Nname.Sym.Name
65
66 funcname := os.Getenv("GOSSAFUNC")
67 if funcname != "" {
68 // If GOSSAFUNC is set, compile only that function.
69 return name == funcname
70 }
71
72 pkg := os.Getenv("GOSSAPKG")
73 if pkg != "" {
74 // If GOSSAPKG is set, compile only that package.
75 return localpkg.Name == pkg
76 }
77
David Chase378a8632016-02-25 13:10:51 -050078 return initssa().DebugHashMatch("GOSSAHASH", name)
Keith Randall5b355a72015-12-11 20:41:52 -080079}
80
81// buildssa builds an SSA function.
82func buildssa(fn *Node) *ssa.Func {
83 name := fn.Func.Nname.Sym.Name
Keith Randall59681802016-03-01 13:47:48 -080084 printssa := name == os.Getenv("GOSSAFUNC")
Keith Randall5b355a72015-12-11 20:41:52 -080085 if printssa {
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -070086 fmt.Println("generating SSA for", name)
Keith Randall4fffd4562016-02-29 13:31:48 -080087 dumpslice("buildssa-enter", fn.Func.Enter.Slice())
Keith Randall9d854fd2016-03-01 12:50:17 -080088 dumpslice("buildssa-body", fn.Nbody.Slice())
Keith Randall4fffd4562016-02-29 13:31:48 -080089 dumpslice("buildssa-exit", fn.Func.Exit.Slice())
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070090 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070091
Keith Randallcfc2aa52015-05-18 16:44:20 -070092 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -040093 s.pushLine(fn.Lineno)
94 defer s.popLine()
95
Keith Randall6a8a9da2016-02-27 17:49:31 -080096 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
97 s.cgoUnsafeArgs = true
98 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070099 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700100
Keith Randall2f57d0f2016-01-28 13:46:30 -0800101 ssaExp.log = printssa
David Chase378a8632016-02-25 13:10:51 -0500102
103 s.config = initssa()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700104 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700105 s.f.Name = name
David Chase8824dcc2015-10-08 12:39:56 -0400106 s.exitCode = fn.Func.Exit
Keith Randall74e568f2015-11-09 21:35:40 -0800107 s.panics = map[funcLine]*ssa.Block{}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700108
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700109 if name == os.Getenv("GOSSAFUNC") {
110 // TODO: tempfile? it is handy to have the location
111 // of this file be stable, so you can just reload in the browser.
Keith Randallda8af472016-01-13 11:14:57 -0800112 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700113 // TODO: generate and print a mapping from nodes to values and blocks
114 }
115 defer func() {
Keith Randall5b355a72015-12-11 20:41:52 -0800116 if !printssa {
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700117 s.config.HTML.Close()
118 }
119 }()
120
Keith Randalld2fd43a2015-04-15 15:51:25 -0700121 // Allocate starting block
122 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
123
Keith Randallcfc2aa52015-05-18 16:44:20 -0700124 // Allocate starting values
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700125 s.labels = map[string]*ssaLabel{}
126 s.labeledNodes = map[*Node]*ssaLabel{}
Keith Randall02f4d0a2015-11-02 08:10:26 -0800127 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -0700128 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
129 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
Keith Randall8c46aa52015-06-19 21:02:28 -0700130
David Chase956f3192015-09-11 16:40:05 -0400131 s.startBlock(s.f.Entry)
132 s.vars[&memVar] = s.startmem
133
Todd Neald076ef72015-10-15 20:25:32 -0500134 s.varsyms = map[*Node]interface{}{}
135
Keith Randall8c46aa52015-06-19 21:02:28 -0700136 // Generate addresses of local declarations
137 s.decladdrs = map[*Node]*ssa.Value{}
Keith Randall4fffd4562016-02-29 13:31:48 -0800138 for _, n := range fn.Func.Dcl {
Keith Randall8c46aa52015-06-19 21:02:28 -0700139 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -0800140 case PPARAM, PPARAMOUT:
Todd Neald076ef72015-10-15 20:25:32 -0500141 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randall8c46aa52015-06-19 21:02:28 -0700142 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800143 if n.Class == PPARAMOUT && s.canSSA(n) {
144 // Save ssa-able PPARAMOUT variables so we can
145 // store them back to the stack at the end of
146 // the function.
147 s.returns = append(s.returns, n)
148 }
David Chase956f3192015-09-11 16:40:05 -0400149 case PAUTO | PHEAP:
150 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
Todd Neald076ef72015-10-15 20:25:32 -0500151 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
David Chase956f3192015-09-11 16:40:05 -0400152 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase8824dcc2015-10-08 12:39:56 -0400153 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
154 // This ends up wrong, have to do it at the PARAM node instead.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800155 case PAUTO:
Keith Randalld2107fc2015-08-24 02:16:19 -0700156 // processed at each use, to prevent Addr coming
157 // before the decl.
Keith Randallc3eb1a72015-09-06 13:42:26 -0700158 case PFUNC:
159 // local function - already handled by frontend
Daniel Morsingbe2a3e22015-07-01 20:37:25 +0100160 default:
161 str := ""
162 if n.Class&PHEAP != 0 {
163 str = ",heap"
164 }
Josh Bleecher Snyder58446032015-08-23 20:29:43 -0700165 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -0700166 }
167 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700168
169 // Convert the AST-based IR to the SSA-based IR
Keith Randall4fffd4562016-02-29 13:31:48 -0800170 s.stmts(fn.Func.Enter)
Keith Randall9d854fd2016-03-01 12:50:17 -0800171 s.stmts(fn.Nbody)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700172
Keith Randallcfc2aa52015-05-18 16:44:20 -0700173 // fallthrough to exit
Keith Randalla7cfc7592015-09-08 16:04:37 -0700174 if s.curBlock != nil {
Keith Randall4fffd4562016-02-29 13:31:48 -0800175 s.stmts(s.exitCode)
Keith Randalla7cfc7592015-09-08 16:04:37 -0700176 m := s.mem()
177 b := s.endBlock()
Keith Randalld9f2caf2015-09-03 14:28:52 -0700178 b.Kind = ssa.BlockRet
Keith Randalla7cfc7592015-09-08 16:04:37 -0700179 b.Control = m
Keith Randallcfc2aa52015-05-18 16:44:20 -0700180 }
181
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700182 // Check that we used all labels
183 for name, lab := range s.labels {
184 if !lab.used() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800185 yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700186 lab.reported = true
187 }
188 if lab.used() && !lab.defined() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800189 yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700190 lab.reported = true
191 }
192 }
193
194 // Check any forward gotos. Non-forward gotos have already been checked.
195 for _, n := range s.fwdGotos {
196 lab := s.labels[n.Left.Sym.Name]
197 // If the label is undefined, we have already have printed an error.
198 if lab.defined() {
199 s.checkgoto(n, lab.defNode)
200 }
201 }
202
203 if nerrors > 0 {
Keith Randall4c5459d2016-01-28 16:11:56 -0800204 s.f.Free()
Keith Randall5b355a72015-12-11 20:41:52 -0800205 return nil
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700206 }
207
Keith Randalld2fd43a2015-04-15 15:51:25 -0700208 // Link up variable uses to variable definitions
209 s.linkForwardReferences()
210
David Chase8824dcc2015-10-08 12:39:56 -0400211 // Don't carry reference this around longer than necessary
Keith Randall4fffd4562016-02-29 13:31:48 -0800212 s.exitCode = Nodes{}
David Chase8824dcc2015-10-08 12:39:56 -0400213
Josh Bleecher Snyder983bc8d2015-07-17 16:47:43 +0000214 // Main call to ssa package to compile function
215 ssa.Compile(s.f)
216
Keith Randall5b355a72015-12-11 20:41:52 -0800217 return s.f
Keith Randalld2fd43a2015-04-15 15:51:25 -0700218}
219
Keith Randallcfc2aa52015-05-18 16:44:20 -0700220type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700221 // configuration (arch) information
222 config *ssa.Config
223
224 // function we're building
225 f *ssa.Func
226
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700227 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
228 labels map[string]*ssaLabel
229 labeledNodes map[*Node]*ssaLabel
230
231 // gotos that jump forward; required for deferred checkgoto calls
232 fwdGotos []*Node
David Chase8824dcc2015-10-08 12:39:56 -0400233 // Code that must precede any return
234 // (e.g., copying value of heap-escaped paramout back to true paramout)
Keith Randall4fffd4562016-02-29 13:31:48 -0800235 exitCode Nodes
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700236
237 // unlabeled break and continue statement tracking
238 breakTo *ssa.Block // current target for plain break statement
239 continueTo *ssa.Block // current target for plain continue statement
Keith Randalld2fd43a2015-04-15 15:51:25 -0700240
241 // current location where we're interpreting the AST
242 curBlock *ssa.Block
243
Keith Randall8c46aa52015-06-19 21:02:28 -0700244 // variable assignments in the current block (map from variable symbol to ssa value)
245 // *Node is the unique identifier (an ONAME Node) for the variable.
246 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700247
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000248 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700249 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700250
Keith Randalld2107fc2015-08-24 02:16:19 -0700251 // addresses of PPARAM and PPARAMOUT variables.
Keith Randall8c46aa52015-06-19 21:02:28 -0700252 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700253
Todd Neald076ef72015-10-15 20:25:32 -0500254 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
255 varsyms map[*Node]interface{}
256
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000257 // starting values. Memory, stack pointer, and globals pointer
Keith Randallcfc2aa52015-05-18 16:44:20 -0700258 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700259 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700260 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400261
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000262 // line number stack. The current line number is top of stack
Michael Matloob81ccf502015-05-30 01:03:06 -0400263 line []int32
Keith Randall74e568f2015-11-09 21:35:40 -0800264
265 // list of panic calls by function name and line number.
266 // Used to deduplicate panic calls.
267 panics map[funcLine]*ssa.Block
Keith Randallb5c5efd2016-01-14 16:02:23 -0800268
269 // list of FwdRef values.
270 fwdRefs []*ssa.Value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800271
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000272 // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800273 returns []*Node
274
275 cgoUnsafeArgs bool
Keith Randall74e568f2015-11-09 21:35:40 -0800276}
277
278type funcLine struct {
279 f *Node
280 line int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700281}
282
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700283type ssaLabel struct {
284 target *ssa.Block // block identified by this label
285 breakTarget *ssa.Block // block to break to in control flow node identified by this label
286 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
287 defNode *Node // label definition Node (OLABEL)
288 // Label use Node (OGOTO, OBREAK, OCONTINUE).
289 // Used only for error detection and reporting.
290 // There might be multiple uses, but we only need to track one.
291 useNode *Node
292 reported bool // reported indicates whether an error has already been reported for this label
293}
294
295// defined reports whether the label has a definition (OLABEL node).
296func (l *ssaLabel) defined() bool { return l.defNode != nil }
297
298// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
299func (l *ssaLabel) used() bool { return l.useNode != nil }
300
301// label returns the label associated with sym, creating it if necessary.
302func (s *state) label(sym *Sym) *ssaLabel {
303 lab := s.labels[sym.Name]
304 if lab == nil {
305 lab = new(ssaLabel)
306 s.labels[sym.Name] = lab
307 }
308 return lab
309}
310
Keith Randallda8af472016-01-13 11:14:57 -0800311func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
David Chase88b230e2016-01-29 14:44:15 -0500312func (s *state) Log() bool { return s.config.Log() }
Keith Randallda8af472016-01-13 11:14:57 -0800313func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
314func (s *state) Unimplementedf(msg string, args ...interface{}) {
315 s.config.Unimplementedf(s.peekLine(), msg, args...)
316}
David Chase729abfa2015-10-26 17:34:06 -0400317func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
318func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700319
Keith Randall269baa92015-09-17 10:31:16 -0700320var (
321 // dummy node for the memory variable
Keith Randallc24681a2015-10-22 14:22:38 -0700322 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
Keith Randall8c46aa52015-06-19 21:02:28 -0700323
Keith Randall269baa92015-09-17 10:31:16 -0700324 // dummy nodes for temporary variables
Keith Randallc24681a2015-10-22 14:22:38 -0700325 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
326 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
327 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
328 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
329 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
Keith Randall269baa92015-09-17 10:31:16 -0700330)
Keith Randall5505e8c2015-09-12 23:27:26 -0700331
Keith Randalld2fd43a2015-04-15 15:51:25 -0700332// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700333func (s *state) startBlock(b *ssa.Block) {
334 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700335 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700336 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700337 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700338 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700339}
340
341// endBlock marks the end of generating code for the current block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000342// Returns the (former) current block. Returns nil if there is no current
Keith Randalld2fd43a2015-04-15 15:51:25 -0700343// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700344func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700345 b := s.curBlock
346 if b == nil {
347 return nil
348 }
349 for len(s.defvars) <= int(b.ID) {
350 s.defvars = append(s.defvars, nil)
351 }
352 s.defvars[b.ID] = s.vars
353 s.curBlock = nil
354 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400355 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700356 return b
357}
358
Michael Matloob81ccf502015-05-30 01:03:06 -0400359// pushLine pushes a line number on the line number stack.
360func (s *state) pushLine(line int32) {
361 s.line = append(s.line, line)
362}
363
364// popLine pops the top of the line number stack.
365func (s *state) popLine() {
366 s.line = s.line[:len(s.line)-1]
367}
368
369// peekLine peek the top of the line number stack.
370func (s *state) peekLine() int32 {
371 return s.line[len(s.line)-1]
372}
373
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700374func (s *state) Error(msg string, args ...interface{}) {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800375 yyerrorl(s.peekLine(), msg, args...)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700376}
377
Keith Randall8f22b522015-06-11 21:29:25 -0700378// newValue0 adds a new value with no arguments to the current block.
379func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
380 return s.curBlock.NewValue0(s.peekLine(), op, t)
381}
382
383// newValue0A adds a new value with no arguments and an aux value to the current block.
384func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
385 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400386}
387
Todd Neal991036a2015-09-03 18:24:22 -0500388// newValue0I adds a new value with no arguments and an auxint value to the current block.
389func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
390 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
391}
392
Michael Matloob81ccf502015-05-30 01:03:06 -0400393// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700394func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
395 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
396}
397
398// newValue1A adds a new value with one argument and an aux value to the current block.
399func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
400 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400401}
402
Keith Randallcd7e0592015-07-15 21:33:49 -0700403// newValue1I adds a new value with one argument and an auxint value to the current block.
404func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
405 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
406}
407
Michael Matloob81ccf502015-05-30 01:03:06 -0400408// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700409func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
410 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400411}
412
Daniel Morsing66b47812015-06-27 15:45:20 +0100413// newValue2I adds a new value with two arguments and an auxint value to the current block.
414func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
415 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
416}
417
Michael Matloob81ccf502015-05-30 01:03:06 -0400418// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700419func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
420 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400421}
422
Keith Randalld4cc51d2015-08-14 21:47:20 -0700423// newValue3I adds a new value with three arguments and an auxint value to the current block.
424func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
425 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
426}
427
Todd Neal991036a2015-09-03 18:24:22 -0500428// entryNewValue0 adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700429func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
430 return s.f.Entry.NewValue0(s.peekLine(), op, t)
431}
432
Todd Neal991036a2015-09-03 18:24:22 -0500433// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700434func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
435 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400436}
437
Todd Neal991036a2015-09-03 18:24:22 -0500438// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
439func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
440 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
441}
442
Michael Matloob81ccf502015-05-30 01:03:06 -0400443// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700444func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
445 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
446}
447
448// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
449func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
450 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400451}
452
Keith Randall8c46aa52015-06-19 21:02:28 -0700453// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
454func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
455 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
456}
457
Michael Matloob81ccf502015-05-30 01:03:06 -0400458// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700459func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
460 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400461}
462
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700463// const* routines add a new const value to the entry block.
464func (s *state) constBool(c bool) *ssa.Value {
465 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
466}
Keith Randall9cb332e2015-07-28 14:19:20 -0700467func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
468 return s.f.ConstInt8(s.peekLine(), t, c)
469}
470func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
471 return s.f.ConstInt16(s.peekLine(), t, c)
472}
473func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
474 return s.f.ConstInt32(s.peekLine(), t, c)
475}
476func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
477 return s.f.ConstInt64(s.peekLine(), t, c)
478}
David Chase997a9f32015-08-12 16:38:11 -0400479func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
480 return s.f.ConstFloat32(s.peekLine(), t, c)
481}
482func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
483 return s.f.ConstFloat64(s.peekLine(), t, c)
484}
Michael Matloob81ccf502015-05-30 01:03:06 -0400485func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
Keith Randall9cb332e2015-07-28 14:19:20 -0700486 if s.config.IntSize == 8 {
487 return s.constInt64(t, c)
488 }
489 if int64(int32(c)) != c {
490 s.Fatalf("integer constant too big %d", c)
491 }
492 return s.constInt32(t, int32(c))
Michael Matloob81ccf502015-05-30 01:03:06 -0400493}
494
Keith Randall4fffd4562016-02-29 13:31:48 -0800495func (s *state) stmts(a Nodes) {
496 for _, x := range a.Slice() {
497 s.stmt(x)
498 }
499}
500
Keith Randalld2fd43a2015-04-15 15:51:25 -0700501// ssaStmtList converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700502func (s *state) stmtList(l *NodeList) {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700503 for ; l != nil; l = l.Next {
504 s.stmt(l.N)
505 }
506}
507
508// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700509func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400510 s.pushLine(n.Lineno)
511 defer s.popLine()
512
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700513 // If s.curBlock is nil, then we're about to generate dead code.
514 // We can't just short-circuit here, though,
515 // because we check labels and gotos as part of SSA generation.
516 // Provide a block for the dead code so that we don't have
517 // to add special cases everywhere else.
518 if s.curBlock == nil {
519 dead := s.f.NewBlock(ssa.BlockPlain)
520 s.startBlock(dead)
521 }
522
Keith Randalld2fd43a2015-04-15 15:51:25 -0700523 s.stmtList(n.Ninit)
524 switch n.Op {
525
526 case OBLOCK:
527 s.stmtList(n.List)
528
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600529 // No-ops
Todd Neal67e43c12015-08-28 21:19:40 -0500530 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600531
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600532 // Expression statements
533 case OCALLFUNC, OCALLMETH, OCALLINTER:
Keith Randalld24768e2015-09-09 23:56:59 -0700534 s.call(n, callNormal)
Keith Randallfb54e032016-02-24 16:19:20 -0800535 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
536 (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
Keith Randall6a8a9da2016-02-27 17:49:31 -0800537 n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800538 m := s.mem()
539 b := s.endBlock()
540 b.Kind = ssa.BlockExit
541 b.Control = m
542 // TODO: never rewrite OPANIC to OCALLFUNC in the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000543 // first place. Need to wait until all backends
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800544 // go through SSA.
545 }
Keith Randalld24768e2015-09-09 23:56:59 -0700546 case ODEFER:
547 s.call(n.Left, callDefer)
548 case OPROC:
549 s.call(n.Left, callGo)
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600550
Keith Randall269baa92015-09-17 10:31:16 -0700551 case OAS2DOTTYPE:
552 res, resok := s.dottype(n.Rlist.N, true)
Keith Randall80bc5122016-02-23 14:32:55 -0800553 s.assign(n.List.N, res, needwritebarrier(n.List.N, n.Rlist.N), false, n.Lineno)
Keith Randall5ba31942016-01-25 17:06:54 -0800554 s.assign(n.List.Next.N, resok, false, false, n.Lineno)
Keith Randall269baa92015-09-17 10:31:16 -0700555 return
556
Keith Randalld2fd43a2015-04-15 15:51:25 -0700557 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100558 if n.Left.Class&PHEAP == 0 {
559 return
560 }
561 if compiling_runtime != 0 {
Keith Randall0ec72b62015-09-08 15:42:53 -0700562 Fatalf("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100563 }
564
565 // TODO: the old pass hides the details of PHEAP
566 // variables behind ONAME nodes. Figure out if it's better
567 // to rewrite the tree and make the heapaddr construct explicit
568 // or to keep this detail hidden behind the scenes.
569 palloc := prealloc[n.Left]
570 if palloc == nil {
571 palloc = callnew(n.Left.Type)
572 prealloc[n.Left] = palloc
573 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700574 r := s.expr(palloc)
Keith Randall5ba31942016-01-25 17:06:54 -0800575 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700576
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700577 case OLABEL:
578 sym := n.Left.Sym
579
580 if isblanksym(sym) {
Keith Randall7e4c06d2015-07-12 11:52:09 -0700581 // Empty identifier is valid but useless.
582 // See issues 11589, 11593.
583 return
584 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700585
586 lab := s.label(sym)
587
588 // Associate label with its control flow node, if any
589 if ctl := n.Name.Defn; ctl != nil {
590 switch ctl.Op {
591 case OFOR, OSWITCH, OSELECT:
592 s.labeledNodes[ctl] = lab
593 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700594 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700595
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700596 if !lab.defined() {
597 lab.defNode = n
598 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800599 s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700600 lab.reported = true
Keith Randalld2fd43a2015-04-15 15:51:25 -0700601 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700602 // The label might already have a target block via a goto.
603 if lab.target == nil {
604 lab.target = s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700605 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700606
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700607 // go to that label (we pretend "label:" is preceded by "goto label")
608 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500609 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700610 s.startBlock(lab.target)
611
612 case OGOTO:
613 sym := n.Left.Sym
614
615 lab := s.label(sym)
616 if lab.target == nil {
617 lab.target = s.f.NewBlock(ssa.BlockPlain)
618 }
619 if !lab.used() {
620 lab.useNode = n
621 }
622
623 if lab.defined() {
624 s.checkgoto(n, lab.defNode)
625 } else {
626 s.fwdGotos = append(s.fwdGotos, n)
627 }
628
629 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500630 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700631
Keith Randall290d8fc2015-06-10 15:03:06 -0700632 case OAS, OASWB:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700633 // Check whether we can generate static data rather than code.
634 // If so, ignore n and defer data generation until codegen.
635 // Failure to do this causes writes to readonly symbols.
636 if gen_as_init(n, true) {
637 var data []*Node
638 if s.f.StaticData != nil {
639 data = s.f.StaticData.([]*Node)
640 }
641 s.f.StaticData = append(data, n)
642 return
643 }
Keith Randall5ba31942016-01-25 17:06:54 -0800644
645 var t *Type
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700646 if n.Right != nil {
Keith Randall5ba31942016-01-25 17:06:54 -0800647 t = n.Right.Type
648 } else {
649 t = n.Left.Type
650 }
651
652 // Evaluate RHS.
653 rhs := n.Right
654 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
655 // All literals with nonzero fields have already been
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000656 // rewritten during walk. Any that remain are just T{}
657 // or equivalents. Use the zero value.
Keith Randall5ba31942016-01-25 17:06:54 -0800658 if !iszero(rhs) {
659 Fatalf("literal with nonzero value in SSA: %v", rhs)
660 }
661 rhs = nil
662 }
663 var r *ssa.Value
664 needwb := n.Op == OASWB && rhs != nil
665 deref := !canSSAType(t)
666 if deref {
667 if rhs == nil {
668 r = nil // Signal assign to use OpZero.
Keith Randalld3886902015-09-18 22:12:38 -0700669 } else {
Keith Randall5ba31942016-01-25 17:06:54 -0800670 r = s.addr(rhs, false)
671 }
672 } else {
673 if rhs == nil {
674 r = s.zeroVal(t)
675 } else {
676 r = s.expr(rhs)
Keith Randalld3886902015-09-18 22:12:38 -0700677 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700678 }
Keith Randall5ba31942016-01-25 17:06:54 -0800679 if rhs != nil && rhs.Op == OAPPEND {
Keith Randall9d22c102015-09-11 11:02:57 -0700680 // Yuck! The frontend gets rid of the write barrier, but we need it!
681 // At least, we need it in the case where growslice is called.
682 // TODO: Do the write barrier on just the growslice branch.
683 // TODO: just add a ptr graying to the end of growslice?
684 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
685 // They get similar wb-removal treatment in walk.go:OAS.
Keith Randall5ba31942016-01-25 17:06:54 -0800686 needwb = true
Keith Randall9d22c102015-09-11 11:02:57 -0700687 }
Keith Randall5ba31942016-01-25 17:06:54 -0800688
689 s.assign(n.Left, r, needwb, deref, n.Lineno)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100690
Keith Randalld2fd43a2015-04-15 15:51:25 -0700691 case OIF:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700692 bThen := s.f.NewBlock(ssa.BlockPlain)
693 bEnd := s.f.NewBlock(ssa.BlockPlain)
694 var bElse *ssa.Block
Keith Randall99187312015-11-02 16:56:53 -0800695 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700696 bElse = s.f.NewBlock(ssa.BlockPlain)
Keith Randall99187312015-11-02 16:56:53 -0800697 s.condBranch(n.Left, bThen, bElse, n.Likely)
698 } else {
699 s.condBranch(n.Left, bThen, bEnd, n.Likely)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700700 }
701
702 s.startBlock(bThen)
Keith Randall9d854fd2016-03-01 12:50:17 -0800703 s.stmts(n.Nbody)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700704 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500705 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700706 }
707
Keith Randalle707fbe2015-06-11 10:20:39 -0700708 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700709 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700710 s.stmtList(n.Rlist)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700711 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500712 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700713 }
714 }
715 s.startBlock(bEnd)
716
717 case ORETURN:
718 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800719 s.exit()
Keith Randall8a1f6212015-09-08 21:28:44 -0700720 case ORETJMP:
721 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800722 b := s.exit()
723 b.Kind = ssa.BlockRetJmp // override BlockRet
Keith Randall8a1f6212015-09-08 21:28:44 -0700724 b.Aux = n.Left.Sym
Keith Randalld2fd43a2015-04-15 15:51:25 -0700725
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700726 case OCONTINUE, OBREAK:
727 var op string
728 var to *ssa.Block
729 switch n.Op {
730 case OCONTINUE:
731 op = "continue"
732 to = s.continueTo
733 case OBREAK:
734 op = "break"
735 to = s.breakTo
736 }
737 if n.Left == nil {
738 // plain break/continue
739 if to == nil {
740 s.Error("%s is not in a loop", op)
741 return
742 }
743 // nothing to do; "to" is already the correct target
744 } else {
745 // labeled break/continue; look up the target
746 sym := n.Left.Sym
747 lab := s.label(sym)
748 if !lab.used() {
749 lab.useNode = n.Left
750 }
751 if !lab.defined() {
752 s.Error("%s label not defined: %v", op, sym)
753 lab.reported = true
754 return
755 }
756 switch n.Op {
757 case OCONTINUE:
758 to = lab.continueTarget
759 case OBREAK:
760 to = lab.breakTarget
761 }
762 if to == nil {
763 // Valid label but not usable with a break/continue here, e.g.:
764 // for {
765 // continue abc
766 // }
767 // abc:
768 // for {}
769 s.Error("invalid %s label %v", op, sym)
770 lab.reported = true
771 return
772 }
773 }
774
775 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500776 b.AddEdgeTo(to)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700777
Keith Randalld2fd43a2015-04-15 15:51:25 -0700778 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700779 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700780 bCond := s.f.NewBlock(ssa.BlockPlain)
781 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700782 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700783 bEnd := s.f.NewBlock(ssa.BlockPlain)
784
785 // first, jump to condition test
786 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500787 b.AddEdgeTo(bCond)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700788
789 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700790 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700791 if n.Left != nil {
Keith Randall99187312015-11-02 16:56:53 -0800792 s.condBranch(n.Left, bBody, bEnd, 1)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700793 } else {
Keith Randall99187312015-11-02 16:56:53 -0800794 b := s.endBlock()
795 b.Kind = ssa.BlockPlain
796 b.AddEdgeTo(bBody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700797 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700798
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700799 // set up for continue/break in body
800 prevContinue := s.continueTo
801 prevBreak := s.breakTo
802 s.continueTo = bIncr
803 s.breakTo = bEnd
804 lab := s.labeledNodes[n]
805 if lab != nil {
806 // labeled for loop
807 lab.continueTarget = bIncr
808 lab.breakTarget = bEnd
809 }
810
Keith Randalld2fd43a2015-04-15 15:51:25 -0700811 // generate body
812 s.startBlock(bBody)
Keith Randall9d854fd2016-03-01 12:50:17 -0800813 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700814
815 // tear down continue/break
816 s.continueTo = prevContinue
817 s.breakTo = prevBreak
818 if lab != nil {
819 lab.continueTarget = nil
820 lab.breakTarget = nil
821 }
822
823 // done with body, goto incr
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700824 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500825 b.AddEdgeTo(bIncr)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700826 }
827
828 // generate incr
829 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700830 if n.Right != nil {
831 s.stmt(n.Right)
832 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700833 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500834 b.AddEdgeTo(bCond)
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700835 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700836 s.startBlock(bEnd)
837
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700838 case OSWITCH, OSELECT:
839 // These have been mostly rewritten by the front end into their Nbody fields.
840 // Our main task is to correctly hook up any break statements.
841 bEnd := s.f.NewBlock(ssa.BlockPlain)
842
843 prevBreak := s.breakTo
844 s.breakTo = bEnd
845 lab := s.labeledNodes[n]
846 if lab != nil {
847 // labeled
848 lab.breakTarget = bEnd
849 }
850
851 // generate body code
Keith Randall9d854fd2016-03-01 12:50:17 -0800852 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700853
854 s.breakTo = prevBreak
855 if lab != nil {
856 lab.breakTarget = nil
857 }
858
Keith Randalleb0cff92016-02-09 12:28:02 -0800859 // OSWITCH never falls through (s.curBlock == nil here).
860 // OSELECT does not fall through if we're calling selectgo.
861 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
862 // In those latter cases, go to the code after the select.
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700863 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500864 b.AddEdgeTo(bEnd)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700865 }
866 s.startBlock(bEnd)
867
Keith Randalld2fd43a2015-04-15 15:51:25 -0700868 case OVARKILL:
Keith Randalld2107fc2015-08-24 02:16:19 -0700869 // Insert a varkill op to record that a variable is no longer live.
870 // We only care about liveness info at call sites, so putting the
871 // varkill in the store chain is enough to keep it correctly ordered
872 // with respect to call ops.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800873 if !s.canSSA(n.Left) {
Keith Randalld29e92b2015-09-19 12:01:39 -0700874 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
875 }
Keith Randall9569b952015-08-28 22:51:01 -0700876
Keith Randall23d58102016-01-19 09:59:21 -0800877 case OVARLIVE:
878 // Insert a varlive op to record that a variable is still live.
879 if !n.Left.Addrtaken {
880 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
881 }
882 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
883
Keith Randall46ffb022015-09-12 14:06:44 -0700884 case OCHECKNIL:
885 p := s.expr(n.Left)
886 s.nilCheck(p)
887
Keith Randalld2fd43a2015-04-15 15:51:25 -0700888 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700889 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700890 }
891}
892
Keith Randall6a8a9da2016-02-27 17:49:31 -0800893// exit processes any code that needs to be generated just before returning.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000894// It returns a BlockRet block that ends the control flow. Its control value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800895// will be set to the final memory state.
896func (s *state) exit() *ssa.Block {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000897 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
Keith Randall6a8a9da2016-02-27 17:49:31 -0800898 // variables back to the stack.
899 s.stmts(s.exitCode)
900
901 // Store SSAable PPARAMOUT variables back to stack locations.
902 for _, n := range s.returns {
903 aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
904 addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
905 val := s.variable(n, n.Type)
906 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
907 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
908 // TODO: if val is ever spilled, we'd like to use the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000909 // PPARAMOUT slot for spilling it. That won't happen
Keith Randall6a8a9da2016-02-27 17:49:31 -0800910 // currently.
911 }
912
913 // Do actual return.
914 m := s.mem()
915 b := s.endBlock()
916 b.Kind = ssa.BlockRet
917 b.Control = m
918 return b
919}
920
Keith Randall67fdb0d2015-07-19 15:48:20 -0700921type opAndType struct {
Keith Randall4304fbc2015-11-16 13:20:16 -0800922 op Op
923 etype EType
Keith Randall67fdb0d2015-07-19 15:48:20 -0700924}
925
926var opToSSA = map[opAndType]ssa.Op{
David Chase997a9f32015-08-12 16:38:11 -0400927 opAndType{OADD, TINT8}: ssa.OpAdd8,
928 opAndType{OADD, TUINT8}: ssa.OpAdd8,
929 opAndType{OADD, TINT16}: ssa.OpAdd16,
930 opAndType{OADD, TUINT16}: ssa.OpAdd16,
931 opAndType{OADD, TINT32}: ssa.OpAdd32,
932 opAndType{OADD, TUINT32}: ssa.OpAdd32,
933 opAndType{OADD, TPTR32}: ssa.OpAdd32,
934 opAndType{OADD, TINT64}: ssa.OpAdd64,
935 opAndType{OADD, TUINT64}: ssa.OpAdd64,
936 opAndType{OADD, TPTR64}: ssa.OpAdd64,
937 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
938 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700939
David Chase997a9f32015-08-12 16:38:11 -0400940 opAndType{OSUB, TINT8}: ssa.OpSub8,
941 opAndType{OSUB, TUINT8}: ssa.OpSub8,
942 opAndType{OSUB, TINT16}: ssa.OpSub16,
943 opAndType{OSUB, TUINT16}: ssa.OpSub16,
944 opAndType{OSUB, TINT32}: ssa.OpSub32,
945 opAndType{OSUB, TUINT32}: ssa.OpSub32,
946 opAndType{OSUB, TINT64}: ssa.OpSub64,
947 opAndType{OSUB, TUINT64}: ssa.OpSub64,
948 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
949 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700950
Josh Bleecher Snydere61e7c92015-07-22 19:19:40 -0700951 opAndType{ONOT, TBOOL}: ssa.OpNot,
952
David Chase3a9d0ac2015-08-28 14:24:10 -0400953 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
954 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
955 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
956 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
957 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
958 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
959 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
960 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
961 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
962 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +0200963
Keith Randall4b803152015-07-29 17:07:09 -0700964 opAndType{OCOM, TINT8}: ssa.OpCom8,
965 opAndType{OCOM, TUINT8}: ssa.OpCom8,
966 opAndType{OCOM, TINT16}: ssa.OpCom16,
967 opAndType{OCOM, TUINT16}: ssa.OpCom16,
968 opAndType{OCOM, TINT32}: ssa.OpCom32,
969 opAndType{OCOM, TUINT32}: ssa.OpCom32,
970 opAndType{OCOM, TINT64}: ssa.OpCom64,
971 opAndType{OCOM, TUINT64}: ssa.OpCom64,
972
Josh Bleecher Snyderfa5fe192015-09-06 19:24:59 -0700973 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
974 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
975 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
976 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
977
David Chase997a9f32015-08-12 16:38:11 -0400978 opAndType{OMUL, TINT8}: ssa.OpMul8,
979 opAndType{OMUL, TUINT8}: ssa.OpMul8,
980 opAndType{OMUL, TINT16}: ssa.OpMul16,
981 opAndType{OMUL, TUINT16}: ssa.OpMul16,
982 opAndType{OMUL, TINT32}: ssa.OpMul32,
983 opAndType{OMUL, TUINT32}: ssa.OpMul32,
984 opAndType{OMUL, TINT64}: ssa.OpMul64,
985 opAndType{OMUL, TUINT64}: ssa.OpMul64,
986 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
987 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
988
989 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
990 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
Keith Randallbe1eb572015-07-22 13:46:15 -0700991
Todd Neal67cbd5b2015-08-18 19:14:47 -0500992 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
993 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
994 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
995 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
996 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
997 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
998
Todd Neala45f2d82015-08-17 17:46:06 -0500999 opAndType{ODIV, TINT8}: ssa.OpDiv8,
1000 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
1001 opAndType{ODIV, TINT16}: ssa.OpDiv16,
1002 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
1003 opAndType{ODIV, TINT32}: ssa.OpDiv32,
1004 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
1005 opAndType{ODIV, TINT64}: ssa.OpDiv64,
1006 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
1007
Todd Neal57d9e7e2015-08-18 19:51:44 -05001008 opAndType{OMOD, TINT8}: ssa.OpMod8,
1009 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1010 opAndType{OMOD, TINT16}: ssa.OpMod16,
1011 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1012 opAndType{OMOD, TINT32}: ssa.OpMod32,
1013 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1014 opAndType{OMOD, TINT64}: ssa.OpMod64,
1015 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1016
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001017 opAndType{OAND, TINT8}: ssa.OpAnd8,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001018 opAndType{OAND, TUINT8}: ssa.OpAnd8,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001019 opAndType{OAND, TINT16}: ssa.OpAnd16,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001020 opAndType{OAND, TUINT16}: ssa.OpAnd16,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001021 opAndType{OAND, TINT32}: ssa.OpAnd32,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001022 opAndType{OAND, TUINT32}: ssa.OpAnd32,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001023 opAndType{OAND, TINT64}: ssa.OpAnd64,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001024 opAndType{OAND, TUINT64}: ssa.OpAnd64,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001025
Alexandru Moșoi74024162015-07-29 17:52:25 +02001026 opAndType{OOR, TINT8}: ssa.OpOr8,
1027 opAndType{OOR, TUINT8}: ssa.OpOr8,
1028 opAndType{OOR, TINT16}: ssa.OpOr16,
1029 opAndType{OOR, TUINT16}: ssa.OpOr16,
1030 opAndType{OOR, TINT32}: ssa.OpOr32,
1031 opAndType{OOR, TUINT32}: ssa.OpOr32,
1032 opAndType{OOR, TINT64}: ssa.OpOr64,
1033 opAndType{OOR, TUINT64}: ssa.OpOr64,
1034
Alexandru Moșoi6d9362a12015-07-30 12:33:36 +02001035 opAndType{OXOR, TINT8}: ssa.OpXor8,
1036 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1037 opAndType{OXOR, TINT16}: ssa.OpXor16,
1038 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1039 opAndType{OXOR, TINT32}: ssa.OpXor32,
1040 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1041 opAndType{OXOR, TINT64}: ssa.OpXor64,
1042 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1043
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001044 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1045 opAndType{OEQ, TINT8}: ssa.OpEq8,
1046 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1047 opAndType{OEQ, TINT16}: ssa.OpEq16,
1048 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1049 opAndType{OEQ, TINT32}: ssa.OpEq32,
1050 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1051 opAndType{OEQ, TINT64}: ssa.OpEq64,
1052 opAndType{OEQ, TUINT64}: ssa.OpEq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001053 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1054 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001055 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1056 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1057 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001058 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001059 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1060 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001061 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1062 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001063
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001064 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1065 opAndType{ONE, TINT8}: ssa.OpNeq8,
1066 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1067 opAndType{ONE, TINT16}: ssa.OpNeq16,
1068 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1069 opAndType{ONE, TINT32}: ssa.OpNeq32,
1070 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1071 opAndType{ONE, TINT64}: ssa.OpNeq64,
1072 opAndType{ONE, TUINT64}: ssa.OpNeq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001073 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1074 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001075 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1076 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1077 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001078 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001079 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1080 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001081 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1082 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001083
David Chase8e601b22015-08-18 14:39:26 -04001084 opAndType{OLT, TINT8}: ssa.OpLess8,
1085 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1086 opAndType{OLT, TINT16}: ssa.OpLess16,
1087 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1088 opAndType{OLT, TINT32}: ssa.OpLess32,
1089 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1090 opAndType{OLT, TINT64}: ssa.OpLess64,
1091 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1092 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1093 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001094
David Chase8e601b22015-08-18 14:39:26 -04001095 opAndType{OGT, TINT8}: ssa.OpGreater8,
1096 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1097 opAndType{OGT, TINT16}: ssa.OpGreater16,
1098 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1099 opAndType{OGT, TINT32}: ssa.OpGreater32,
1100 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1101 opAndType{OGT, TINT64}: ssa.OpGreater64,
1102 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1103 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1104 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001105
David Chase8e601b22015-08-18 14:39:26 -04001106 opAndType{OLE, TINT8}: ssa.OpLeq8,
1107 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1108 opAndType{OLE, TINT16}: ssa.OpLeq16,
1109 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1110 opAndType{OLE, TINT32}: ssa.OpLeq32,
1111 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1112 opAndType{OLE, TINT64}: ssa.OpLeq64,
1113 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1114 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1115 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001116
David Chase8e601b22015-08-18 14:39:26 -04001117 opAndType{OGE, TINT8}: ssa.OpGeq8,
1118 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1119 opAndType{OGE, TINT16}: ssa.OpGeq16,
1120 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1121 opAndType{OGE, TINT32}: ssa.OpGeq32,
1122 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1123 opAndType{OGE, TINT64}: ssa.OpGeq64,
1124 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1125 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1126 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
David Chase40aba8c2015-08-05 22:11:14 -04001127
1128 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1129 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1130 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1131 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
Keith Randalla329e212015-09-12 13:26:57 -07001132
1133 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001134}
1135
Keith Randall4304fbc2015-11-16 13:20:16 -08001136func (s *state) concreteEtype(t *Type) EType {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001137 e := t.Etype
1138 switch e {
1139 default:
1140 return e
Keith Randall67fdb0d2015-07-19 15:48:20 -07001141 case TINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001142 if s.config.IntSize == 8 {
1143 return TINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001144 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001145 return TINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001146 case TUINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001147 if s.config.IntSize == 8 {
1148 return TUINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001149 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001150 return TUINT32
1151 case TUINTPTR:
1152 if s.config.PtrSize == 8 {
1153 return TUINT64
1154 }
1155 return TUINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001156 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001157}
1158
Keith Randall4304fbc2015-11-16 13:20:16 -08001159func (s *state) ssaOp(op Op, t *Type) ssa.Op {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001160 etype := s.concreteEtype(t)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001161 x, ok := opToSSA[opAndType{op, etype}]
1162 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001163 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
Keith Randall67fdb0d2015-07-19 15:48:20 -07001164 }
1165 return x
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001166}
1167
David Chase3a9d0ac2015-08-28 14:24:10 -04001168func floatForComplex(t *Type) *Type {
1169 if t.Size() == 8 {
1170 return Types[TFLOAT32]
1171 } else {
1172 return Types[TFLOAT64]
1173 }
1174}
1175
Keith Randall4b803152015-07-29 17:07:09 -07001176type opAndTwoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001177 op Op
1178 etype1 EType
1179 etype2 EType
Keith Randall4b803152015-07-29 17:07:09 -07001180}
1181
David Chased052bbd2015-09-01 17:09:00 -04001182type twoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001183 etype1 EType
1184 etype2 EType
David Chased052bbd2015-09-01 17:09:00 -04001185}
1186
1187type twoOpsAndType struct {
1188 op1 ssa.Op
1189 op2 ssa.Op
Keith Randall4304fbc2015-11-16 13:20:16 -08001190 intermediateType EType
David Chased052bbd2015-09-01 17:09:00 -04001191}
1192
1193var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1194
1195 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1196 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1197 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1198 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1199
1200 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1201 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1202 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1203 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1204
1205 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1206 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1207 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1208 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1209
1210 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1211 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1212 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1213 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1214 // unsigned
1215 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1216 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1217 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1218 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1219
1220 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1221 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1222 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1223 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1224
1225 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1226 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1227 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1228 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1229
1230 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1231 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1232 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1233 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1234
1235 // float
1236 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1237 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1238 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1239 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1240}
1241
Keith Randall4b803152015-07-29 17:07:09 -07001242var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1243 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1244 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1245 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1246 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1247 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1248 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1249 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1250 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1251
1252 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1253 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1254 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1255 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1256 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1257 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1258 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1259 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1260
1261 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1262 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1263 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1264 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1265 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1266 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1267 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1268 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1269
1270 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1271 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1272 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1273 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1274 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1275 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1276 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1277 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1278
1279 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1280 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1281 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1282 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1283 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1284 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1285 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1286 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1287
1288 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1289 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1290 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1291 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1292 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1293 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1294 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1295 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1296
1297 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1298 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1299 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1300 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1301 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1302 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1303 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1304 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1305
1306 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1307 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1308 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1309 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1310 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1311 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1312 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1313 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1314}
1315
Keith Randall4304fbc2015-11-16 13:20:16 -08001316func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
Keith Randall4b803152015-07-29 17:07:09 -07001317 etype1 := s.concreteEtype(t)
1318 etype2 := s.concreteEtype(u)
1319 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1320 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001321 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
Keith Randall4b803152015-07-29 17:07:09 -07001322 }
1323 return x
1324}
1325
Keith Randall4304fbc2015-11-16 13:20:16 -08001326func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
David Chase40aba8c2015-08-05 22:11:14 -04001327 etype1 := s.concreteEtype(t)
1328 x, ok := opToSSA[opAndType{op, etype1}]
1329 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001330 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
David Chase40aba8c2015-08-05 22:11:14 -04001331 }
1332 return x
1333}
1334
Keith Randalld2fd43a2015-04-15 15:51:25 -07001335// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -07001336func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -04001337 s.pushLine(n.Lineno)
1338 defer s.popLine()
1339
Keith Randall06f32922015-07-11 11:39:12 -07001340 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001341 switch n.Op {
Todd Nealdef7c652015-09-07 19:07:02 -05001342 case OCFUNC:
Todd Neald076ef72015-10-15 20:25:32 -05001343 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
Todd Nealdef7c652015-09-07 19:07:02 -05001344 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
David Chase956f3192015-09-11 16:40:05 -04001345 case OPARAM:
David Chase57670ad2015-10-09 16:48:30 -04001346 addr := s.addr(n, false)
David Chase32ffbf72015-10-08 17:14:12 -04001347 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001348 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07001349 if n.Class == PFUNC {
1350 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -07001351 sym := funcsym(n.Sym)
1352 aux := &ssa.ExternSymbol{n.Type, sym}
1353 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -07001354 }
Keith Randall6a8a9da2016-02-27 17:49:31 -08001355 if s.canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -07001356 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -07001357 }
David Chase57670ad2015-10-09 16:48:30 -04001358 addr := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001359 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
David Chase956f3192015-09-11 16:40:05 -04001360 case OCLOSUREVAR:
David Chase57670ad2015-10-09 16:48:30 -04001361 addr := s.addr(n, false)
David Chase956f3192015-09-11 16:40:05 -04001362 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001363 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -07001364 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -07001365 case CTINT:
Keith Randall9cb332e2015-07-28 14:19:20 -07001366 i := Mpgetfix(n.Val().U.(*Mpint))
1367 switch n.Type.Size() {
1368 case 1:
1369 return s.constInt8(n.Type, int8(i))
1370 case 2:
1371 return s.constInt16(n.Type, int16(i))
1372 case 4:
1373 return s.constInt32(n.Type, int32(i))
1374 case 8:
1375 return s.constInt64(n.Type, i)
1376 default:
1377 s.Fatalf("bad integer size %d", n.Type.Size())
1378 return nil
1379 }
1380 case CTSTR:
1381 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1382 case CTBOOL:
Keith Randallb5c5efd2016-01-14 16:02:23 -08001383 v := s.constBool(n.Val().U.(bool))
1384 // For some reason the frontend gets the line numbers of
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001385 // CTBOOL literals totally wrong. Fix it here by grabbing
Keith Randallb5c5efd2016-01-14 16:02:23 -08001386 // the line number of the enclosing AST node.
1387 if len(s.line) >= 2 {
1388 v.Line = s.line[len(s.line)-2]
1389 }
1390 return v
Brad Fitzpatrick337b7e72015-07-13 17:30:42 -06001391 case CTNIL:
Keith Randall9f954db2015-08-18 10:26:28 -07001392 t := n.Type
1393 switch {
1394 case t.IsSlice():
1395 return s.entryNewValue0(ssa.OpConstSlice, t)
1396 case t.IsInterface():
1397 return s.entryNewValue0(ssa.OpConstInterface, t)
1398 default:
1399 return s.entryNewValue0(ssa.OpConstNil, t)
1400 }
David Chase997a9f32015-08-12 16:38:11 -04001401 case CTFLT:
1402 f := n.Val().U.(*Mpflt)
1403 switch n.Type.Size() {
1404 case 4:
Keith Randall733bf6e2016-01-25 20:26:06 -08001405 return s.constFloat32(n.Type, mpgetflt32(f))
David Chase997a9f32015-08-12 16:38:11 -04001406 case 8:
Keith Randall733bf6e2016-01-25 20:26:06 -08001407 return s.constFloat64(n.Type, mpgetflt(f))
David Chase997a9f32015-08-12 16:38:11 -04001408 default:
1409 s.Fatalf("bad float size %d", n.Type.Size())
1410 return nil
1411 }
David Chase52578582015-08-28 14:24:10 -04001412 case CTCPLX:
1413 c := n.Val().U.(*Mpcplx)
1414 r := &c.Real
1415 i := &c.Imag
1416 switch n.Type.Size() {
1417 case 8:
1418 {
1419 pt := Types[TFLOAT32]
1420 return s.newValue2(ssa.OpComplexMake, n.Type,
Keith Randall733bf6e2016-01-25 20:26:06 -08001421 s.constFloat32(pt, mpgetflt32(r)),
1422 s.constFloat32(pt, mpgetflt32(i)))
David Chase52578582015-08-28 14:24:10 -04001423 }
1424 case 16:
1425 {
1426 pt := Types[TFLOAT64]
1427 return s.newValue2(ssa.OpComplexMake, n.Type,
Keith Randall733bf6e2016-01-25 20:26:06 -08001428 s.constFloat64(pt, mpgetflt(r)),
1429 s.constFloat64(pt, mpgetflt(i)))
David Chase52578582015-08-28 14:24:10 -04001430 }
1431 default:
1432 s.Fatalf("bad float size %d", n.Type.Size())
1433 return nil
1434 }
David Chase997a9f32015-08-12 16:38:11 -04001435
Keith Randalld2fd43a2015-04-15 15:51:25 -07001436 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001437 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001438 return nil
1439 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001440 case OCONVNOP:
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001441 to := n.Type
1442 from := n.Left.Type
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001443
1444 // Assume everything will work out, so set up our return value.
1445 // Anything interesting that happens from here is a fatal.
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001446 x := s.expr(n.Left)
David Chasee99dd522015-10-19 11:36:07 -04001447
1448 // Special case for not confusing GC and liveness.
1449 // We don't want pointers accidentally classified
1450 // as not-pointers or vice-versa because of copy
1451 // elision.
1452 if to.IsPtr() != from.IsPtr() {
Keith Randall7807bda2015-11-10 15:35:36 -08001453 return s.newValue2(ssa.OpConvert, to, x, s.mem())
David Chasee99dd522015-10-19 11:36:07 -04001454 }
1455
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001456 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1457
Todd Nealdef7c652015-09-07 19:07:02 -05001458 // CONVNOP closure
1459 if to.Etype == TFUNC && from.IsPtr() {
1460 return v
1461 }
1462
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001463 // named <--> unnamed type or typed <--> untyped const
1464 if from.Etype == to.Etype {
1465 return v
1466 }
David Chasee99dd522015-10-19 11:36:07 -04001467
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001468 // unsafe.Pointer <--> *T
1469 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1470 return v
1471 }
1472
1473 dowidth(from)
1474 dowidth(to)
1475 if from.Width != to.Width {
1476 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1477 return nil
1478 }
1479 if etypesign(from.Etype) != etypesign(to.Etype) {
Keith Randall4304fbc2015-11-16 13:20:16 -08001480 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001481 return nil
1482 }
1483
Ian Lance Taylor88e18032016-03-01 15:17:34 -08001484 if instrumenting {
David Chase57670ad2015-10-09 16:48:30 -04001485 // These appear to be fine, but they fail the
1486 // integer constraint below, so okay them here.
1487 // Sample non-integer conversion: map[string]string -> *uint8
1488 return v
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001489 }
1490
1491 if etypesign(from.Etype) == 0 {
1492 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1493 return nil
1494 }
1495
1496 // integer, same width, same sign
1497 return v
1498
Michael Matloob73054f52015-06-14 11:38:46 -07001499 case OCONV:
1500 x := s.expr(n.Left)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001501 ft := n.Left.Type // from type
1502 tt := n.Type // to type
1503 if ft.IsInteger() && tt.IsInteger() {
1504 var op ssa.Op
1505 if tt.Size() == ft.Size() {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001506 op = ssa.OpCopy
Keith Randall2a5e6c42015-07-23 14:35:02 -07001507 } else if tt.Size() < ft.Size() {
1508 // truncation
1509 switch 10*ft.Size() + tt.Size() {
1510 case 21:
1511 op = ssa.OpTrunc16to8
1512 case 41:
1513 op = ssa.OpTrunc32to8
1514 case 42:
1515 op = ssa.OpTrunc32to16
1516 case 81:
1517 op = ssa.OpTrunc64to8
1518 case 82:
1519 op = ssa.OpTrunc64to16
1520 case 84:
1521 op = ssa.OpTrunc64to32
1522 default:
1523 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1524 }
1525 } else if ft.IsSigned() {
1526 // sign extension
1527 switch 10*ft.Size() + tt.Size() {
1528 case 12:
1529 op = ssa.OpSignExt8to16
1530 case 14:
1531 op = ssa.OpSignExt8to32
1532 case 18:
1533 op = ssa.OpSignExt8to64
1534 case 24:
1535 op = ssa.OpSignExt16to32
1536 case 28:
1537 op = ssa.OpSignExt16to64
1538 case 48:
1539 op = ssa.OpSignExt32to64
1540 default:
1541 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1542 }
1543 } else {
1544 // zero extension
1545 switch 10*ft.Size() + tt.Size() {
1546 case 12:
1547 op = ssa.OpZeroExt8to16
1548 case 14:
1549 op = ssa.OpZeroExt8to32
1550 case 18:
1551 op = ssa.OpZeroExt8to64
1552 case 24:
1553 op = ssa.OpZeroExt16to32
1554 case 28:
1555 op = ssa.OpZeroExt16to64
1556 case 48:
1557 op = ssa.OpZeroExt32to64
1558 default:
1559 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1560 }
1561 }
1562 return s.newValue1(op, n.Type, x)
1563 }
David Chase42825882015-08-20 15:14:20 -04001564
David Chased052bbd2015-09-01 17:09:00 -04001565 if ft.IsFloat() || tt.IsFloat() {
1566 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1567 if !ok {
1568 s.Fatalf("weird float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001569 }
David Chased052bbd2015-09-01 17:09:00 -04001570 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1571
1572 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1573 // normal case, not tripping over unsigned 64
1574 if op1 == ssa.OpCopy {
1575 if op2 == ssa.OpCopy {
1576 return x
1577 }
1578 return s.newValue1(op2, n.Type, x)
1579 }
1580 if op2 == ssa.OpCopy {
1581 return s.newValue1(op1, n.Type, x)
1582 }
1583 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1584 }
1585 // Tricky 64-bit unsigned cases.
1586 if ft.IsInteger() {
1587 // therefore tt is float32 or float64, and ft is also unsigned
David Chase42825882015-08-20 15:14:20 -04001588 if tt.Size() == 4 {
1589 return s.uint64Tofloat32(n, x, ft, tt)
1590 }
1591 if tt.Size() == 8 {
1592 return s.uint64Tofloat64(n, x, ft, tt)
1593 }
David Chased052bbd2015-09-01 17:09:00 -04001594 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001595 }
David Chased052bbd2015-09-01 17:09:00 -04001596 // therefore ft is float32 or float64, and tt is unsigned integer
David Chase73151062015-08-26 14:25:40 -04001597 if ft.Size() == 4 {
David Chased052bbd2015-09-01 17:09:00 -04001598 return s.float32ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001599 }
David Chased052bbd2015-09-01 17:09:00 -04001600 if ft.Size() == 8 {
1601 return s.float64ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001602 }
David Chased052bbd2015-09-01 17:09:00 -04001603 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1604 return nil
David Chase42825882015-08-20 15:14:20 -04001605 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001606
1607 if ft.IsComplex() && tt.IsComplex() {
1608 var op ssa.Op
1609 if ft.Size() == tt.Size() {
1610 op = ssa.OpCopy
1611 } else if ft.Size() == 8 && tt.Size() == 16 {
1612 op = ssa.OpCvt32Fto64F
1613 } else if ft.Size() == 16 && tt.Size() == 8 {
1614 op = ssa.OpCvt64Fto32F
1615 } else {
1616 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1617 }
1618 ftp := floatForComplex(ft)
1619 ttp := floatForComplex(tt)
1620 return s.newValue2(ssa.OpComplexMake, tt,
1621 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1622 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1623 }
David Chase42825882015-08-20 15:14:20 -04001624
Keith Randall4304fbc2015-11-16 13:20:16 -08001625 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
Keith Randall2a5e6c42015-07-23 14:35:02 -07001626 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001627
Keith Randall269baa92015-09-17 10:31:16 -07001628 case ODOTTYPE:
1629 res, _ := s.dottype(n, false)
1630 return res
1631
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001632 // binary ops
1633 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001634 a := s.expr(n.Left)
1635 b := s.expr(n.Right)
Keith Randalldb380bf2015-09-10 11:05:42 -07001636 if n.Left.Type.IsComplex() {
Keith Randallc244ce02015-09-10 14:59:00 -07001637 pt := floatForComplex(n.Left.Type)
Keith Randalldb380bf2015-09-10 11:05:42 -07001638 op := s.ssaOp(OEQ, pt)
1639 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1640 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1641 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1642 switch n.Op {
1643 case OEQ:
1644 return c
1645 case ONE:
1646 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1647 default:
1648 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1649 }
Keith Randalldb380bf2015-09-10 11:05:42 -07001650 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001651 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
David Chase3a9d0ac2015-08-28 14:24:10 -04001652 case OMUL:
1653 a := s.expr(n.Left)
1654 b := s.expr(n.Right)
1655 if n.Type.IsComplex() {
1656 mulop := ssa.OpMul64F
1657 addop := ssa.OpAdd64F
1658 subop := ssa.OpSub64F
1659 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1660 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1661
1662 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1663 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1664 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1665 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1666
1667 if pt != wt { // Widen for calculation
1668 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1669 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1670 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1671 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1672 }
1673
1674 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1675 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1676
1677 if pt != wt { // Narrow to store back
1678 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1679 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1680 }
1681
1682 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1683 }
1684 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1685
1686 case ODIV:
1687 a := s.expr(n.Left)
1688 b := s.expr(n.Right)
1689 if n.Type.IsComplex() {
1690 // TODO this is not executed because the front-end substitutes a runtime call.
1691 // That probably ought to change; with modest optimization the widen/narrow
1692 // conversions could all be elided in larger expression trees.
1693 mulop := ssa.OpMul64F
1694 addop := ssa.OpAdd64F
1695 subop := ssa.OpSub64F
1696 divop := ssa.OpDiv64F
1697 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1698 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1699
1700 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1701 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1702 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1703 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1704
1705 if pt != wt { // Widen for calculation
1706 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1707 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1708 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1709 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1710 }
1711
1712 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1713 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1714 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1715
1716 // TODO not sure if this is best done in wide precision or narrow
1717 // Double-rounding might be an issue.
1718 // Note that the pre-SSA implementation does the entire calculation
1719 // in wide format, so wide is compatible.
1720 xreal = s.newValue2(divop, wt, xreal, denom)
1721 ximag = s.newValue2(divop, wt, ximag, denom)
1722
1723 if pt != wt { // Narrow to store back
1724 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1725 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1726 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001727 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1728 }
David Chase18559e22015-10-28 13:55:46 -04001729 if n.Type.IsFloat() {
1730 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1731 } else {
1732 // do a size-appropriate check for zero
1733 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1734 s.check(cmp, panicdivide)
1735 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1736 }
1737 case OMOD:
1738 a := s.expr(n.Left)
1739 b := s.expr(n.Right)
1740 // do a size-appropriate check for zero
1741 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1742 s.check(cmp, panicdivide)
David Chase3a9d0ac2015-08-28 14:24:10 -04001743 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1744 case OADD, OSUB:
1745 a := s.expr(n.Left)
1746 b := s.expr(n.Right)
1747 if n.Type.IsComplex() {
1748 pt := floatForComplex(n.Type)
1749 op := s.ssaOp(n.Op, pt)
1750 return s.newValue2(ssa.OpComplexMake, n.Type,
1751 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1752 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1753 }
1754 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
David Chase18559e22015-10-28 13:55:46 -04001755 case OAND, OOR, OHMUL, OXOR:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001756 a := s.expr(n.Left)
1757 b := s.expr(n.Right)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001758 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
Keith Randall4b803152015-07-29 17:07:09 -07001759 case OLSH, ORSH:
1760 a := s.expr(n.Left)
1761 b := s.expr(n.Right)
1762 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
David Chase40aba8c2015-08-05 22:11:14 -04001763 case OLROT:
1764 a := s.expr(n.Left)
1765 i := n.Right.Int()
1766 if i <= 0 || i >= n.Type.Size()*8 {
1767 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1768 }
1769 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001770 case OANDAND, OOROR:
1771 // To implement OANDAND (and OOROR), we introduce a
1772 // new temporary variable to hold the result. The
1773 // variable is associated with the OANDAND node in the
1774 // s.vars table (normally variables are only
1775 // associated with ONAME nodes). We convert
1776 // A && B
1777 // to
1778 // var = A
1779 // if var {
1780 // var = B
1781 // }
1782 // Using var in the subsequent block introduces the
1783 // necessary phi variable.
1784 el := s.expr(n.Left)
1785 s.vars[n] = el
1786
1787 b := s.endBlock()
1788 b.Kind = ssa.BlockIf
1789 b.Control = el
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07001790 // In theory, we should set b.Likely here based on context.
1791 // However, gc only gives us likeliness hints
1792 // in a single place, for plain OIF statements,
1793 // and passing around context is finnicky, so don't bother for now.
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001794
1795 bRight := s.f.NewBlock(ssa.BlockPlain)
1796 bResult := s.f.NewBlock(ssa.BlockPlain)
1797 if n.Op == OANDAND {
Todd Neal47d67992015-08-28 21:36:29 -05001798 b.AddEdgeTo(bRight)
1799 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001800 } else if n.Op == OOROR {
Todd Neal47d67992015-08-28 21:36:29 -05001801 b.AddEdgeTo(bResult)
1802 b.AddEdgeTo(bRight)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001803 }
1804
1805 s.startBlock(bRight)
1806 er := s.expr(n.Right)
1807 s.vars[n] = er
1808
1809 b = s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05001810 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001811
1812 s.startBlock(bResult)
Josh Bleecher Snyder35ad1fc2015-08-27 10:11:08 -07001813 return s.variable(n, Types[TBOOL])
Keith Randall7e390722015-09-12 14:14:02 -07001814 case OCOMPLEX:
1815 r := s.expr(n.Left)
1816 i := s.expr(n.Right)
1817 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001818
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001819 // unary ops
David Chase3a9d0ac2015-08-28 14:24:10 -04001820 case OMINUS:
1821 a := s.expr(n.Left)
1822 if n.Type.IsComplex() {
1823 tp := floatForComplex(n.Type)
1824 negop := s.ssaOp(n.Op, tp)
1825 return s.newValue2(ssa.OpComplexMake, n.Type,
1826 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1827 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1828 }
1829 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randalla329e212015-09-12 13:26:57 -07001830 case ONOT, OCOM, OSQRT:
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001831 a := s.expr(n.Left)
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001832 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randall2f518072015-09-10 11:37:09 -07001833 case OIMAG, OREAL:
1834 a := s.expr(n.Left)
1835 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001836 case OPLUS:
1837 return s.expr(n.Left)
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001838
Keith Randallcfc2aa52015-05-18 16:44:20 -07001839 case OADDR:
David Chase57670ad2015-10-09 16:48:30 -04001840 return s.addr(n.Left, n.Bounded)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001841
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07001842 case OINDREG:
1843 if int(n.Reg) != Thearch.REGSP {
1844 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1845 return nil
1846 }
1847 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1848 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1849
Keith Randalld2fd43a2015-04-15 15:51:25 -07001850 case OIND:
1851 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001852 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -07001853 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001854
Keith Randallcd7e0592015-07-15 21:33:49 -07001855 case ODOT:
Keith Randalla734bbc2016-01-11 21:05:33 -08001856 t := n.Left.Type
1857 if canSSAType(t) {
1858 v := s.expr(n.Left)
1859 return s.newValue1I(ssa.OpStructSelect, n.Type, fieldIdx(n), v)
1860 }
David Chase57670ad2015-10-09 16:48:30 -04001861 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001862 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcd7e0592015-07-15 21:33:49 -07001863
Keith Randalld2fd43a2015-04-15 15:51:25 -07001864 case ODOTPTR:
1865 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001866 s.nilCheck(p)
Keith Randall582baae2015-11-02 21:28:13 -08001867 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
Keith Randall8f22b522015-06-11 21:29:25 -07001868 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001869
1870 case OINDEX:
Keith Randall97035642015-10-09 09:33:29 -07001871 switch {
1872 case n.Left.Type.IsString():
Keith Randallcfc2aa52015-05-18 16:44:20 -07001873 a := s.expr(n.Left)
1874 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001875 i = s.extendIndex(i)
Keith Randall97035642015-10-09 09:33:29 -07001876 if !n.Bounded {
1877 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1878 s.boundsCheck(i, len)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07001879 }
Keith Randall97035642015-10-09 09:33:29 -07001880 ptrtyp := Ptrto(Types[TUINT8])
1881 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1882 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1883 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1884 case n.Left.Type.IsSlice():
David Chase57670ad2015-10-09 16:48:30 -04001885 p := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001886 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001887 case n.Left.Type.IsArray():
1888 // TODO: fix when we can SSA arrays of length 1.
David Chase57670ad2015-10-09 16:48:30 -04001889 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001890 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1891 default:
1892 s.Fatalf("bad type for index %v", n.Left.Type)
1893 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001894 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07001895
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001896 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001897 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001898 case n.Left.Type.IsSlice():
1899 op := ssa.OpSliceLen
1900 if n.Op == OCAP {
1901 op = ssa.OpSliceCap
1902 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001903 return s.newValue1(op, Types[TINT], s.expr(n.Left))
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001904 case n.Left.Type.IsString(): // string; not reachable for OCAP
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001905 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
Todd Neal707af252015-08-28 15:56:43 -05001906 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1907 return s.referenceTypeBuiltin(n, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001908 default: // array
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001909 return s.constInt(Types[TINT], n.Left.Type.Bound)
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001910 }
1911
Josh Bleecher Snydera2d15802015-08-12 10:12:14 -07001912 case OSPTR:
1913 a := s.expr(n.Left)
1914 if n.Left.Type.IsSlice() {
1915 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1916 } else {
1917 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1918 }
1919
Keith Randalld1c15a02015-08-04 15:47:22 -07001920 case OITAB:
1921 a := s.expr(n.Left)
1922 return s.newValue1(ssa.OpITab, n.Type, a)
1923
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001924 case OEFACE:
1925 tab := s.expr(n.Left)
1926 data := s.expr(n.Right)
Keith Randall808d7c72015-10-07 14:35:25 -07001927 // The frontend allows putting things like struct{*byte} in
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001928 // the data portion of an eface. But we don't want struct{*byte}
Keith Randall808d7c72015-10-07 14:35:25 -07001929 // as a register type because (among other reasons) the liveness
1930 // analysis is confused by the "fat" variables that result from
1931 // such types being spilled.
1932 // So here we ensure that we are selecting the underlying pointer
1933 // when we build an eface.
Keith Randalla734bbc2016-01-11 21:05:33 -08001934 // TODO: get rid of this now that structs can be SSA'd?
Keith Randall808d7c72015-10-07 14:35:25 -07001935 for !data.Type.IsPtr() {
1936 switch {
1937 case data.Type.IsArray():
Keith Randall62ac1072016-03-01 15:59:15 -08001938 data = s.newValue1I(ssa.OpArrayIndex, data.Type.Elem(), 0, data)
Keith Randall808d7c72015-10-07 14:35:25 -07001939 case data.Type.IsStruct():
1940 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1941 f := data.Type.FieldType(i)
1942 if f.Size() == 0 {
1943 // eface type could also be struct{p *byte; q [0]int}
1944 continue
1945 }
Keith Randalla734bbc2016-01-11 21:05:33 -08001946 data = s.newValue1I(ssa.OpStructSelect, f, i, data)
Keith Randall808d7c72015-10-07 14:35:25 -07001947 break
1948 }
1949 default:
1950 s.Fatalf("type being put into an eface isn't a pointer")
1951 }
1952 }
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001953 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1954
Keith Randall5505e8c2015-09-12 23:27:26 -07001955 case OSLICE, OSLICEARR:
1956 v := s.expr(n.Left)
1957 var i, j *ssa.Value
1958 if n.Right.Left != nil {
1959 i = s.extendIndex(s.expr(n.Right.Left))
1960 }
1961 if n.Right.Right != nil {
1962 j = s.extendIndex(s.expr(n.Right.Right))
1963 }
1964 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1965 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07001966 case OSLICESTR:
Keith Randall5505e8c2015-09-12 23:27:26 -07001967 v := s.expr(n.Left)
1968 var i, j *ssa.Value
1969 if n.Right.Left != nil {
1970 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001971 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001972 if n.Right.Right != nil {
1973 j = s.extendIndex(s.expr(n.Right.Right))
Keith Randall3526cf52015-08-24 23:52:03 -07001974 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001975 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1976 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1977 case OSLICE3, OSLICE3ARR:
1978 v := s.expr(n.Left)
1979 var i *ssa.Value
1980 if n.Right.Left != nil {
1981 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001982 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001983 j := s.extendIndex(s.expr(n.Right.Right.Left))
1984 k := s.extendIndex(s.expr(n.Right.Right.Right))
1985 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1986 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07001987
Keith Randalld24768e2015-09-09 23:56:59 -07001988 case OCALLFUNC, OCALLINTER, OCALLMETH:
Keith Randall5ba31942016-01-25 17:06:54 -08001989 a := s.call(n, callNormal)
1990 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07001991
1992 case OGETG:
Keith Randalld694f832015-10-19 18:54:40 -07001993 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07001994
Keith Randall9d22c102015-09-11 11:02:57 -07001995 case OAPPEND:
1996 // append(s, e1, e2, e3). Compile like:
1997 // ptr,len,cap := s
1998 // newlen := len + 3
1999 // if newlen > s.cap {
2000 // ptr,_,cap = growslice(s, newlen)
2001 // }
2002 // *(ptr+len) = e1
2003 // *(ptr+len+1) = e2
2004 // *(ptr+len+2) = e3
2005 // makeslice(ptr,newlen,cap)
2006
2007 et := n.Type.Type
2008 pt := Ptrto(et)
2009
2010 // Evaluate slice
2011 slice := s.expr(n.List.N)
2012
Keith Randall9d22c102015-09-11 11:02:57 -07002013 // Allocate new blocks
2014 grow := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002015 assign := s.f.NewBlock(ssa.BlockPlain)
2016
2017 // Decide if we need to grow
Keith Randall9aba7e72015-10-05 13:48:40 -07002018 nargs := int64(count(n.List) - 1)
Keith Randall9d22c102015-09-11 11:02:57 -07002019 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2020 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2021 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2022 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2023 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
Keith Randallb32217a2015-09-17 16:45:10 -07002024 s.vars[&ptrVar] = p
2025 s.vars[&capVar] = c
Keith Randall9d22c102015-09-11 11:02:57 -07002026 b := s.endBlock()
2027 b.Kind = ssa.BlockIf
2028 b.Likely = ssa.BranchUnlikely
2029 b.Control = cmp
2030 b.AddEdgeTo(grow)
2031 b.AddEdgeTo(assign)
2032
2033 // Call growslice
2034 s.startBlock(grow)
2035 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
2036
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002037 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
Keith Randall9d22c102015-09-11 11:02:57 -07002038
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002039 s.vars[&ptrVar] = r[0]
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002040 // Note: we don't need to read r[1], the result's length. It will be nl.
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002041 // (or maybe we should, we just have to spill/restore nl otherwise?)
2042 s.vars[&capVar] = r[2]
Keith Randall9d22c102015-09-11 11:02:57 -07002043 b = s.endBlock()
2044 b.AddEdgeTo(assign)
2045
2046 // assign new elements to slots
2047 s.startBlock(assign)
Keith Randall9aba7e72015-10-05 13:48:40 -07002048
2049 // Evaluate args
2050 args := make([]*ssa.Value, 0, nargs)
Keith Randall808d7c72015-10-07 14:35:25 -07002051 store := make([]bool, 0, nargs)
Keith Randall9aba7e72015-10-05 13:48:40 -07002052 for l := n.List.Next; l != nil; l = l.Next {
Keith Randall808d7c72015-10-07 14:35:25 -07002053 if canSSAType(l.N.Type) {
2054 args = append(args, s.expr(l.N))
2055 store = append(store, true)
2056 } else {
David Chase57670ad2015-10-09 16:48:30 -04002057 args = append(args, s.addr(l.N, false))
Keith Randall808d7c72015-10-07 14:35:25 -07002058 store = append(store, false)
2059 }
Keith Randall9aba7e72015-10-05 13:48:40 -07002060 }
2061
Keith Randallb32217a2015-09-17 16:45:10 -07002062 p = s.variable(&ptrVar, pt) // generates phi for ptr
2063 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
Keith Randall9d22c102015-09-11 11:02:57 -07002064 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
Keith Randall5ba31942016-01-25 17:06:54 -08002065 // TODO: just one write barrier call for all of these writes?
2066 // TODO: maybe just one writeBarrier.enabled check?
Keith Randall9d22c102015-09-11 11:02:57 -07002067 for i, arg := range args {
Keith Randall582baae2015-11-02 21:28:13 -08002068 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
Keith Randall808d7c72015-10-07 14:35:25 -07002069 if store[i] {
Keith Randall5ba31942016-01-25 17:06:54 -08002070 if haspointers(et) {
2071 s.insertWBstore(et, addr, arg, n.Lineno)
2072 } else {
2073 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2074 }
Keith Randall808d7c72015-10-07 14:35:25 -07002075 } else {
Keith Randall5ba31942016-01-25 17:06:54 -08002076 if haspointers(et) {
2077 s.insertWBmove(et, addr, arg, n.Lineno)
2078 } else {
2079 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2080 }
Keith Randall9d22c102015-09-11 11:02:57 -07002081 }
2082 }
2083
2084 // make result
Keith Randallb32217a2015-09-17 16:45:10 -07002085 delete(s.vars, &ptrVar)
2086 delete(s.vars, &capVar)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002087 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
Keith Randall9d22c102015-09-11 11:02:57 -07002088
Keith Randalld2fd43a2015-04-15 15:51:25 -07002089 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07002090 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -07002091 return nil
2092 }
2093}
2094
Keith Randall99187312015-11-02 16:56:53 -08002095// condBranch evaluates the boolean expression cond and branches to yes
2096// if cond is true and no if cond is false.
2097// This function is intended to handle && and || better than just calling
2098// s.expr(cond) and branching on the result.
2099func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2100 if cond.Op == OANDAND {
2101 mid := s.f.NewBlock(ssa.BlockPlain)
2102 s.stmtList(cond.Ninit)
2103 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2104 s.startBlock(mid)
2105 s.condBranch(cond.Right, yes, no, likely)
2106 return
2107 // Note: if likely==1, then both recursive calls pass 1.
2108 // If likely==-1, then we don't have enough information to decide
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002109 // whether the first branch is likely or not. So we pass 0 for
Keith Randall99187312015-11-02 16:56:53 -08002110 // the likeliness of the first branch.
2111 // TODO: have the frontend give us branch prediction hints for
2112 // OANDAND and OOROR nodes (if it ever has such info).
2113 }
2114 if cond.Op == OOROR {
2115 mid := s.f.NewBlock(ssa.BlockPlain)
2116 s.stmtList(cond.Ninit)
2117 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2118 s.startBlock(mid)
2119 s.condBranch(cond.Right, yes, no, likely)
2120 return
2121 // Note: if likely==-1, then both recursive calls pass -1.
2122 // If likely==1, then we don't have enough info to decide
2123 // the likelihood of the first branch.
2124 }
Keith Randalld19bfc32015-11-03 09:30:17 -08002125 if cond.Op == ONOT {
2126 s.stmtList(cond.Ninit)
2127 s.condBranch(cond.Left, no, yes, -likely)
2128 return
2129 }
Keith Randall99187312015-11-02 16:56:53 -08002130 c := s.expr(cond)
2131 b := s.endBlock()
2132 b.Kind = ssa.BlockIf
2133 b.Control = c
2134 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2135 b.AddEdgeTo(yes)
2136 b.AddEdgeTo(no)
2137}
2138
Keith Randall5ba31942016-01-25 17:06:54 -08002139// assign does left = right.
2140// Right has already been evaluated to ssa, left has not.
2141// If deref is true, then we do left = *right instead (and right has already been nil-checked).
2142// If deref is true and right == nil, just do left = 0.
2143// Include a write barrier if wb is true.
2144func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002145 if left.Op == ONAME && isblank(left) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002146 return
2147 }
Keith Randalld4cc51d2015-08-14 21:47:20 -07002148 t := left.Type
2149 dowidth(t)
Keith Randall6a8a9da2016-02-27 17:49:31 -08002150 if s.canSSA(left) {
Keith Randall5ba31942016-01-25 17:06:54 -08002151 if deref {
2152 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2153 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002154 if left.Op == ODOT {
2155 // We're assigning to a field of an ssa-able value.
2156 // We need to build a new structure with the new value for the
2157 // field we're assigning and the old values for the other fields.
2158 // For instance:
2159 // type T struct {a, b, c int}
2160 // var T x
2161 // x.b = 5
2162 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2163
2164 // Grab information about the structure type.
2165 t := left.Left.Type
2166 nf := t.NumFields()
2167 idx := fieldIdx(left)
2168
2169 // Grab old value of structure.
2170 old := s.expr(left.Left)
2171
2172 // Make new structure.
2173 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2174
2175 // Add fields as args.
2176 for i := int64(0); i < nf; i++ {
2177 if i == idx {
2178 new.AddArg(right)
2179 } else {
2180 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), i, old))
2181 }
2182 }
2183
2184 // Recursively assign the new value we've made to the base of the dot op.
Keith Randall5ba31942016-01-25 17:06:54 -08002185 s.assign(left.Left, new, false, false, line)
Keith Randalla734bbc2016-01-11 21:05:33 -08002186 // TODO: do we need to update named values here?
2187 return
2188 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002189 // Update variable assignment.
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002190 s.vars[left] = right
Keith Randallc24681a2015-10-22 14:22:38 -07002191 s.addNamedValue(left, right)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002192 return
2193 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002194 // Left is not ssa-able. Compute its address.
David Chase57670ad2015-10-09 16:48:30 -04002195 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002196 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002197 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002198 }
Keith Randall5ba31942016-01-25 17:06:54 -08002199 if deref {
2200 // Treat as a mem->mem move.
2201 if right == nil {
2202 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2203 return
2204 }
2205 if wb {
2206 s.insertWBmove(t, addr, right, line)
2207 return
2208 }
2209 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2210 return
Keith Randalle3869a62015-09-07 23:18:02 -07002211 }
Keith Randall5ba31942016-01-25 17:06:54 -08002212 // Treat as a store.
2213 if wb {
2214 s.insertWBstore(t, addr, right, line)
2215 return
2216 }
2217 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002218}
2219
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002220// zeroVal returns the zero value for type t.
2221func (s *state) zeroVal(t *Type) *ssa.Value {
2222 switch {
Keith Randall9cb332e2015-07-28 14:19:20 -07002223 case t.IsInteger():
2224 switch t.Size() {
2225 case 1:
2226 return s.constInt8(t, 0)
2227 case 2:
2228 return s.constInt16(t, 0)
2229 case 4:
2230 return s.constInt32(t, 0)
2231 case 8:
2232 return s.constInt64(t, 0)
2233 default:
2234 s.Fatalf("bad sized integer type %s", t)
2235 }
Todd Neal752fe4d2015-08-25 19:21:45 -05002236 case t.IsFloat():
2237 switch t.Size() {
2238 case 4:
2239 return s.constFloat32(t, 0)
2240 case 8:
2241 return s.constFloat64(t, 0)
2242 default:
2243 s.Fatalf("bad sized float type %s", t)
2244 }
David Chase52578582015-08-28 14:24:10 -04002245 case t.IsComplex():
2246 switch t.Size() {
2247 case 8:
2248 z := s.constFloat32(Types[TFLOAT32], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002249 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002250 case 16:
2251 z := s.constFloat64(Types[TFLOAT64], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002252 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002253 default:
2254 s.Fatalf("bad sized complex type %s", t)
2255 }
2256
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002257 case t.IsString():
Keith Randall9cb332e2015-07-28 14:19:20 -07002258 return s.entryNewValue0A(ssa.OpConstString, t, "")
2259 case t.IsPtr():
2260 return s.entryNewValue0(ssa.OpConstNil, t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002261 case t.IsBoolean():
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07002262 return s.constBool(false)
Keith Randall9f954db2015-08-18 10:26:28 -07002263 case t.IsInterface():
2264 return s.entryNewValue0(ssa.OpConstInterface, t)
2265 case t.IsSlice():
2266 return s.entryNewValue0(ssa.OpConstSlice, t)
Keith Randalla734bbc2016-01-11 21:05:33 -08002267 case t.IsStruct():
2268 n := t.NumFields()
2269 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
2270 for i := int64(0); i < n; i++ {
2271 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2272 }
2273 return v
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002274 }
2275 s.Unimplementedf("zero for type %v not implemented", t)
2276 return nil
2277}
2278
Keith Randalld24768e2015-09-09 23:56:59 -07002279type callKind int8
2280
2281const (
2282 callNormal callKind = iota
2283 callDefer
2284 callGo
2285)
2286
Keith Randall5ba31942016-01-25 17:06:54 -08002287// Calls the function n using the specified call type.
2288// Returns the address of the return value (or nil if none).
Keith Randalld24768e2015-09-09 23:56:59 -07002289func (s *state) call(n *Node, k callKind) *ssa.Value {
2290 var sym *Sym // target symbol (if static)
2291 var closure *ssa.Value // ptr to closure to run (if dynamic)
2292 var codeptr *ssa.Value // ptr to target code (if dynamic)
2293 var rcvr *ssa.Value // receiver to set
2294 fn := n.Left
2295 switch n.Op {
2296 case OCALLFUNC:
2297 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2298 sym = fn.Sym
2299 break
2300 }
2301 closure = s.expr(fn)
Keith Randalld24768e2015-09-09 23:56:59 -07002302 case OCALLMETH:
2303 if fn.Op != ODOTMETH {
2304 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2305 }
2306 if fn.Right.Op != ONAME {
2307 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2308 }
2309 if k == callNormal {
2310 sym = fn.Right.Sym
2311 break
2312 }
2313 n2 := *fn.Right
2314 n2.Class = PFUNC
2315 closure = s.expr(&n2)
2316 // Note: receiver is already assigned in n.List, so we don't
2317 // want to set it here.
2318 case OCALLINTER:
2319 if fn.Op != ODOTINTER {
2320 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2321 }
2322 i := s.expr(fn.Left)
2323 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2324 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2325 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2326 if k == callNormal {
2327 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2328 } else {
2329 closure = itab
2330 }
2331 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2332 }
2333 dowidth(fn.Type)
2334 stksize := fn.Type.Argwid // includes receiver
2335
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002336 // Run all argument assignments. The arg slots have already
Keith Randalld24768e2015-09-09 23:56:59 -07002337 // been offset by the appropriate amount (+2*widthptr for go/defer,
2338 // +widthptr for interface calls).
2339 // For OCALLMETH, the receiver is set in these statements.
2340 s.stmtList(n.List)
2341
2342 // Set receiver (for interface calls)
2343 if rcvr != nil {
Keith Randall7c4fbb62015-10-19 13:56:55 -07002344 argStart := Ctxt.FixedFrameSize()
Keith Randalld24768e2015-09-09 23:56:59 -07002345 if k != callNormal {
2346 argStart += int64(2 * Widthptr)
2347 }
2348 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002349 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002350 }
2351
2352 // Defer/go args
2353 if k != callNormal {
2354 // Write argsize and closure (args to Newproc/Deferproc).
2355 argsize := s.constInt32(Types[TUINT32], int32(stksize))
Keith Randallb32217a2015-09-17 16:45:10 -07002356 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002357 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002358 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002359 stksize += 2 * int64(Widthptr)
2360 }
2361
2362 // call target
2363 bNext := s.f.NewBlock(ssa.BlockPlain)
2364 var call *ssa.Value
2365 switch {
2366 case k == callDefer:
2367 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2368 case k == callGo:
2369 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2370 case closure != nil:
2371 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2372 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2373 case codeptr != nil:
2374 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2375 case sym != nil:
2376 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2377 default:
2378 Fatalf("bad call type %s %v", opnames[n.Op], n)
2379 }
2380 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2381
2382 // Finish call block
Keith Randallb32217a2015-09-17 16:45:10 -07002383 s.vars[&memVar] = call
Keith Randalld24768e2015-09-09 23:56:59 -07002384 b := s.endBlock()
2385 b.Kind = ssa.BlockCall
2386 b.Control = call
2387 b.AddEdgeTo(bNext)
2388
Keith Randall5ba31942016-01-25 17:06:54 -08002389 // Start exit block, find address of result.
Keith Randalld24768e2015-09-09 23:56:59 -07002390 s.startBlock(bNext)
2391 var titer Iter
2392 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2393 if fp == nil || k != callNormal {
2394 // call has no return value. Continue with the next statement.
2395 return nil
2396 }
Keith Randall5ba31942016-01-25 17:06:54 -08002397 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
Keith Randalld24768e2015-09-09 23:56:59 -07002398}
2399
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002400// etypesign returns the signed-ness of e, for integer/pointer etypes.
2401// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
Keith Randall4304fbc2015-11-16 13:20:16 -08002402func etypesign(e EType) int8 {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002403 switch e {
2404 case TINT8, TINT16, TINT32, TINT64, TINT:
2405 return -1
2406 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2407 return +1
2408 }
2409 return 0
2410}
2411
Todd Neald076ef72015-10-15 20:25:32 -05002412// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2413// This improves the effectiveness of cse by using the same Aux values for the
2414// same symbols.
2415func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2416 switch sym.(type) {
2417 default:
2418 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2419 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2420 // these are the only valid types
2421 }
2422
2423 if lsym, ok := s.varsyms[n]; ok {
2424 return lsym
2425 } else {
2426 s.varsyms[n] = sym
2427 return sym
2428 }
2429}
2430
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07002431// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
Keith Randallc3c84a22015-07-13 15:55:37 -07002432// The value that the returned Value represents is guaranteed to be non-nil.
David Chase57670ad2015-10-09 16:48:30 -04002433// If bounded is true then this address does not require a nil check for its operand
2434// even if that would otherwise be implied.
2435func (s *state) addr(n *Node, bounded bool) *ssa.Value {
Keith Randallc24681a2015-10-22 14:22:38 -07002436 t := Ptrto(n.Type)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002437 switch n.Op {
2438 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07002439 switch n.Class {
2440 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -07002441 // global variable
Todd Neal74180dd2015-10-27 21:35:48 -05002442 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
Keith Randallc24681a2015-10-22 14:22:38 -07002443 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
Josh Bleecher Snyder67df7932015-07-28 11:08:44 -07002444 // TODO: Make OpAddr use AuxInt as well as Aux.
2445 if n.Xoffset != 0 {
2446 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2447 }
2448 return v
David Chase956f3192015-09-11 16:40:05 -04002449 case PPARAM:
2450 // parameter slot
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002451 v := s.decladdrs[n]
Keith Randall4304fbc2015-11-16 13:20:16 -08002452 if v != nil {
2453 return v
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002454 }
Keith Randall4304fbc2015-11-16 13:20:16 -08002455 if n.String() == ".fp" {
2456 // Special arg that points to the frame pointer.
2457 // (Used by the race detector, others?)
2458 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2459 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2460 }
2461 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2462 return nil
Keith Randalld2107fc2015-08-24 02:16:19 -07002463 case PAUTO:
2464 // We need to regenerate the address of autos
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002465 // at every use. This prevents LEA instructions
Keith Randalld2107fc2015-08-24 02:16:19 -07002466 // from occurring before the corresponding VarDef
2467 // op and confusing the liveness analysis into thinking
2468 // the variable is live at function entry.
2469 // TODO: I'm not sure if this really works or we're just
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002470 // getting lucky. We might need a real dependency edge
Keith Randalld2107fc2015-08-24 02:16:19 -07002471 // between vardef and addr ops.
2472 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
Keith Randallc24681a2015-10-22 14:22:38 -07002473 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002474 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
Todd Neald076ef72015-10-15 20:25:32 -05002475 // ensure that we reuse symbols for out parameters so
2476 // that cse works on their addresses
2477 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002478 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002479 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002480 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -07002481 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002482 s.Unimplementedf("variable address class %v not implemented", n.Class)
Keith Randall290d8fc2015-06-10 15:03:06 -07002483 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07002484 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002485 case OINDREG:
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002486 // indirect off a register
Keith Randallcfc2aa52015-05-18 16:44:20 -07002487 // used for storing/loading arguments/returns to/from callees
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002488 if int(n.Reg) != Thearch.REGSP {
2489 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2490 return nil
2491 }
Keith Randallc24681a2015-10-22 14:22:38 -07002492 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002493 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002494 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002495 a := s.expr(n.Left)
2496 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002497 i = s.extendIndex(i)
Keith Randallc24681a2015-10-22 14:22:38 -07002498 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
Keith Randall46e62f82015-08-18 14:17:30 -07002499 if !n.Bounded {
2500 s.boundsCheck(i, len)
2501 }
Keith Randallc24681a2015-10-22 14:22:38 -07002502 p := s.newValue1(ssa.OpSlicePtr, t, a)
2503 return s.newValue2(ssa.OpPtrIndex, t, p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002504 } else { // array
David Chase57670ad2015-10-09 16:48:30 -04002505 a := s.addr(n.Left, bounded)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002506 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002507 i = s.extendIndex(i)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002508 len := s.constInt(Types[TINT], n.Left.Type.Bound)
Keith Randall46e62f82015-08-18 14:17:30 -07002509 if !n.Bounded {
2510 s.boundsCheck(i, len)
2511 }
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002512 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002513 }
Todd Nealb383de22015-07-13 21:22:16 -05002514 case OIND:
2515 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002516 if !bounded {
2517 s.nilCheck(p)
2518 }
Todd Nealb383de22015-07-13 21:22:16 -05002519 return p
Keith Randallc3c84a22015-07-13 15:55:37 -07002520 case ODOT:
David Chase57670ad2015-10-09 16:48:30 -04002521 p := s.addr(n.Left, bounded)
Keith Randall582baae2015-11-02 21:28:13 -08002522 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
Keith Randallc3c84a22015-07-13 15:55:37 -07002523 case ODOTPTR:
2524 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002525 if !bounded {
2526 s.nilCheck(p)
2527 }
Keith Randall582baae2015-11-02 21:28:13 -08002528 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
David Chase956f3192015-09-11 16:40:05 -04002529 case OCLOSUREVAR:
Keith Randallc24681a2015-10-22 14:22:38 -07002530 return s.newValue2(ssa.OpAddPtr, t,
Keith Randall129261a2015-10-27 10:15:02 -07002531 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
Keith Randall582baae2015-11-02 21:28:13 -08002532 s.constInt(Types[TINT], n.Xoffset))
David Chase32ffbf72015-10-08 17:14:12 -04002533 case OPARAM:
2534 p := n.Left
2535 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2536 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2537 }
2538
2539 // Recover original offset to address passed-in param value.
2540 original_p := *p
2541 original_p.Xoffset = n.Xoffset
2542 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
Keith Randallc24681a2015-10-22 14:22:38 -07002543 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase57670ad2015-10-09 16:48:30 -04002544 case OCONVNOP:
2545 addr := s.addr(n.Left, bounded)
Keith Randallc24681a2015-10-22 14:22:38 -07002546 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
Keith Randall5ba31942016-01-25 17:06:54 -08002547 case OCALLFUNC, OCALLINTER, OCALLMETH:
2548 return s.call(n, callNormal)
David Chase57670ad2015-10-09 16:48:30 -04002549
Keith Randallcfc2aa52015-05-18 16:44:20 -07002550 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002551 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -07002552 return nil
2553 }
2554}
2555
Keith Randall290d8fc2015-06-10 15:03:06 -07002556// canSSA reports whether n is SSA-able.
Keith Randalla734bbc2016-01-11 21:05:33 -08002557// n must be an ONAME (or an ODOT sequence with an ONAME base).
Keith Randall6a8a9da2016-02-27 17:49:31 -08002558func (s *state) canSSA(n *Node) bool {
Keith Randalla734bbc2016-01-11 21:05:33 -08002559 for n.Op == ODOT {
2560 n = n.Left
2561 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002562 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +01002563 return false
Keith Randall290d8fc2015-06-10 15:03:06 -07002564 }
2565 if n.Addrtaken {
2566 return false
2567 }
2568 if n.Class&PHEAP != 0 {
2569 return false
2570 }
Josh Bleecher Snyder96548732015-08-28 13:35:32 -07002571 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -08002572 case PEXTERN, PPARAMREF:
2573 // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
Keith Randall290d8fc2015-06-10 15:03:06 -07002574 return false
Keith Randall6a8a9da2016-02-27 17:49:31 -08002575 case PPARAMOUT:
2576 if hasdefer {
2577 // TODO: handle this case? Named return values must be
2578 // in memory so that the deferred function can see them.
2579 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
2580 return false
2581 }
2582 if s.cgoUnsafeArgs {
2583 // Cgo effectively takes the address of all result args,
2584 // but the compiler can't see that.
2585 return false
2586 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002587 }
Keith Randall8a1f6212015-09-08 21:28:44 -07002588 if n.Class == PPARAM && n.String() == ".this" {
2589 // wrappers generated by genwrapper need to update
2590 // the .this pointer in place.
Keith Randall6a8a9da2016-02-27 17:49:31 -08002591 // TODO: treat as a PPARMOUT?
Keith Randall8a1f6212015-09-08 21:28:44 -07002592 return false
2593 }
Keith Randall9f954db2015-08-18 10:26:28 -07002594 return canSSAType(n.Type)
2595 // TODO: try to make more variables SSAable?
2596}
2597
2598// canSSA reports whether variables of type t are SSA-able.
2599func canSSAType(t *Type) bool {
2600 dowidth(t)
2601 if t.Width > int64(4*Widthptr) {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002602 // 4*Widthptr is an arbitrary constant. We want it
Keith Randall9f954db2015-08-18 10:26:28 -07002603 // to be at least 3*Widthptr so slices can be registerized.
2604 // Too big and we'll introduce too much register pressure.
Daniel Morsing66b47812015-06-27 15:45:20 +01002605 return false
2606 }
Keith Randall9f954db2015-08-18 10:26:28 -07002607 switch t.Etype {
2608 case TARRAY:
2609 if Isslice(t) {
2610 return true
2611 }
2612 // We can't do arrays because dynamic indexing is
2613 // not supported on SSA variables.
2614 // TODO: maybe allow if length is <=1? All indexes
2615 // are constant? Might be good for the arrays
2616 // introduced by the compiler for variadic functions.
2617 return false
2618 case TSTRUCT:
Keith Randalla734bbc2016-01-11 21:05:33 -08002619 if countfield(t) > ssa.MaxStruct {
Keith Randall9f954db2015-08-18 10:26:28 -07002620 return false
2621 }
2622 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2623 if !canSSAType(t1.Type) {
2624 return false
2625 }
2626 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002627 return true
Keith Randall9f954db2015-08-18 10:26:28 -07002628 default:
2629 return true
2630 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002631}
2632
Keith Randallcfc2aa52015-05-18 16:44:20 -07002633// nilCheck generates nil pointer checking code.
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002634// Starts a new block on return, unless nil checks are disabled.
Josh Bleecher Snyder7e74e432015-07-24 11:55:52 -07002635// Used only for automatically inserted nil checks,
2636// not for user code like 'x != nil'.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002637func (s *state) nilCheck(ptr *ssa.Value) {
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002638 if Disable_checknil != 0 {
2639 return
2640 }
Keith Randall31115a52015-10-23 19:12:49 -07002641 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07002642 b := s.endBlock()
Keith Randall31115a52015-10-23 19:12:49 -07002643 b.Kind = ssa.BlockCheck
2644 b.Control = chk
Keith Randallcfc2aa52015-05-18 16:44:20 -07002645 bNext := s.f.NewBlock(ssa.BlockPlain)
Todd Neal47d67992015-08-28 21:36:29 -05002646 b.AddEdgeTo(bNext)
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002647 s.startBlock(bNext)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002648}
2649
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002650// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002651// Starts a new block on return.
2652func (s *state) boundsCheck(idx, len *ssa.Value) {
Keith Randall8d236812015-08-18 15:25:40 -07002653 if Debug['B'] != 0 {
2654 return
2655 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002656 // TODO: convert index to full width?
2657 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2658
2659 // bounds check
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002660 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002661 s.check(cmp, Panicindex)
Keith Randall3526cf52015-08-24 23:52:03 -07002662}
2663
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002664// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
Keith Randall3526cf52015-08-24 23:52:03 -07002665// Starts a new block on return.
2666func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2667 if Debug['B'] != 0 {
2668 return
2669 }
2670 // TODO: convert index to full width?
2671 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2672
2673 // bounds check
2674 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002675 s.check(cmp, panicslice)
Keith Randall3526cf52015-08-24 23:52:03 -07002676}
2677
Keith Randall3a70bf92015-09-17 16:54:15 -07002678// If cmp (a bool) is true, panic using the given function.
2679func (s *state) check(cmp *ssa.Value, fn *Node) {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002680 b := s.endBlock()
2681 b.Kind = ssa.BlockIf
2682 b.Control = cmp
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07002683 b.Likely = ssa.BranchLikely
Keith Randallcfc2aa52015-05-18 16:44:20 -07002684 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall74e568f2015-11-09 21:35:40 -08002685 line := s.peekLine()
2686 bPanic := s.panics[funcLine{fn, line}]
2687 if bPanic == nil {
2688 bPanic = s.f.NewBlock(ssa.BlockPlain)
2689 s.panics[funcLine{fn, line}] = bPanic
2690 s.startBlock(bPanic)
2691 // The panic call takes/returns memory to ensure that the right
2692 // memory state is observed if the panic happens.
2693 s.rtcall(fn, false, nil)
2694 }
Todd Neal47d67992015-08-28 21:36:29 -05002695 b.AddEdgeTo(bNext)
2696 b.AddEdgeTo(bPanic)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002697 s.startBlock(bNext)
2698}
2699
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002700// rtcall issues a call to the given runtime function fn with the listed args.
2701// Returns a slice of results of the given result types.
2702// The call is added to the end of the current block.
2703// If returns is false, the block is marked as an exit block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002704// If returns is true, the block is marked as a call block. A new block
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002705// is started to load the return values.
2706func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2707 // Write args to the stack
2708 var off int64 // TODO: arch-dependent starting offset?
2709 for _, arg := range args {
2710 t := arg.Type
2711 off = Rnd(off, t.Alignment())
2712 ptr := s.sp
2713 if off != 0 {
2714 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2715 }
2716 size := t.Size()
2717 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2718 off += size
2719 }
2720 off = Rnd(off, int64(Widthptr))
2721
2722 // Issue call
2723 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2724 s.vars[&memVar] = call
2725
2726 // Finish block
2727 b := s.endBlock()
2728 if !returns {
2729 b.Kind = ssa.BlockExit
2730 b.Control = call
2731 call.AuxInt = off
2732 if len(results) > 0 {
2733 Fatalf("panic call can't have results")
2734 }
2735 return nil
2736 }
2737 b.Kind = ssa.BlockCall
2738 b.Control = call
2739 bNext := s.f.NewBlock(ssa.BlockPlain)
2740 b.AddEdgeTo(bNext)
2741 s.startBlock(bNext)
2742
2743 // Load results
2744 res := make([]*ssa.Value, len(results))
2745 for i, t := range results {
2746 off = Rnd(off, t.Alignment())
2747 ptr := s.sp
2748 if off != 0 {
2749 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2750 }
2751 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2752 off += t.Size()
2753 }
2754 off = Rnd(off, int64(Widthptr))
2755
2756 // Remember how much callee stack space we needed.
2757 call.AuxInt = off
2758
2759 return res
2760}
2761
Keith Randall5ba31942016-01-25 17:06:54 -08002762// insertWBmove inserts the assignment *left = *right including a write barrier.
2763// t is the type being assigned.
2764func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
Keith Randall4304fbc2015-11-16 13:20:16 -08002765 // if writeBarrier.enabled {
Keith Randall5ba31942016-01-25 17:06:54 -08002766 // typedmemmove(&t, left, right)
2767 // } else {
2768 // *left = *right
Keith Randall9d22c102015-09-11 11:02:57 -07002769 // }
2770 bThen := s.f.NewBlock(ssa.BlockPlain)
Keith Randall5ba31942016-01-25 17:06:54 -08002771 bElse := s.f.NewBlock(ssa.BlockPlain)
2772 bEnd := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002773
Keith Randall4304fbc2015-11-16 13:20:16 -08002774 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
David Chase8107b002016-02-28 11:15:22 -05002775 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002776 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002777 // Load word, test byte, avoiding partial register write from load byte.
2778 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2779 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall9d22c102015-09-11 11:02:57 -07002780 b := s.endBlock()
2781 b.Kind = ssa.BlockIf
2782 b.Likely = ssa.BranchUnlikely
2783 b.Control = flag
2784 b.AddEdgeTo(bThen)
Keith Randall5ba31942016-01-25 17:06:54 -08002785 b.AddEdgeTo(bElse)
Keith Randall9d22c102015-09-11 11:02:57 -07002786
2787 s.startBlock(bThen)
Keith Randall9d22c102015-09-11 11:02:57 -07002788 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
Keith Randall5ba31942016-01-25 17:06:54 -08002789 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2790 s.endBlock().AddEdgeTo(bEnd)
2791
2792 s.startBlock(bElse)
2793 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2794 s.endBlock().AddEdgeTo(bEnd)
2795
2796 s.startBlock(bEnd)
Keith Randall9d22c102015-09-11 11:02:57 -07002797
David Chase729abfa2015-10-26 17:34:06 -04002798 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002799 Warnl(line, "write barrier")
David Chase729abfa2015-10-26 17:34:06 -04002800 }
Keith Randall5ba31942016-01-25 17:06:54 -08002801}
David Chase729abfa2015-10-26 17:34:06 -04002802
Keith Randall5ba31942016-01-25 17:06:54 -08002803// insertWBstore inserts the assignment *left = right including a write barrier.
2804// t is the type being assigned.
2805func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32) {
2806 // store scalar fields
2807 // if writeBarrier.enabled {
2808 // writebarrierptr for pointer fields
2809 // } else {
2810 // store pointer fields
2811 // }
2812
Keith Randallaebf6612016-01-29 21:57:57 -08002813 s.storeTypeScalars(t, left, right)
Keith Randall5ba31942016-01-25 17:06:54 -08002814
2815 bThen := s.f.NewBlock(ssa.BlockPlain)
2816 bElse := s.f.NewBlock(ssa.BlockPlain)
2817 bEnd := s.f.NewBlock(ssa.BlockPlain)
2818
2819 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
David Chase8107b002016-02-28 11:15:22 -05002820 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002821 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002822 // Load word, test byte, avoiding partial register write from load byte.
2823 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2824 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall5ba31942016-01-25 17:06:54 -08002825 b := s.endBlock()
2826 b.Kind = ssa.BlockIf
2827 b.Likely = ssa.BranchUnlikely
2828 b.Control = flag
2829 b.AddEdgeTo(bThen)
2830 b.AddEdgeTo(bElse)
2831
2832 // Issue write barriers for pointer writes.
2833 s.startBlock(bThen)
Keith Randallaebf6612016-01-29 21:57:57 -08002834 s.storeTypePtrsWB(t, left, right)
2835 s.endBlock().AddEdgeTo(bEnd)
2836
2837 // Issue regular stores for pointer writes.
2838 s.startBlock(bElse)
2839 s.storeTypePtrs(t, left, right)
2840 s.endBlock().AddEdgeTo(bEnd)
2841
2842 s.startBlock(bEnd)
2843
2844 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002845 Warnl(line, "write barrier")
Keith Randallaebf6612016-01-29 21:57:57 -08002846 }
2847}
2848
2849// do *left = right for all scalar (non-pointer) parts of t.
2850func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value) {
2851 switch {
2852 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
2853 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
2854 case t.IsPtr() || t.IsMap() || t.IsChan():
2855 // no scalar fields.
2856 case t.IsString():
2857 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
2858 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2859 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2860 case t.IsSlice():
2861 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
2862 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
2863 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2864 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2865 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
2866 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
2867 case t.IsInterface():
2868 // itab field doesn't need a write barrier (even though it is a pointer).
2869 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
2870 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
2871 case t.IsStruct():
2872 n := t.NumFields()
2873 for i := int64(0); i < n; i++ {
2874 ft := t.FieldType(i)
2875 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2876 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2877 s.storeTypeScalars(ft.(*Type), addr, val)
2878 }
2879 default:
2880 s.Fatalf("bad write barrier type %s", t)
2881 }
2882}
2883
2884// do *left = right for all pointer parts of t.
2885func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
2886 switch {
2887 case t.IsPtr() || t.IsMap() || t.IsChan():
2888 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
2889 case t.IsString():
2890 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2891 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2892 case t.IsSlice():
2893 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2894 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2895 case t.IsInterface():
2896 // itab field is treated as a scalar.
2897 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2898 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2899 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
2900 case t.IsStruct():
2901 n := t.NumFields()
2902 for i := int64(0); i < n; i++ {
2903 ft := t.FieldType(i)
2904 if !haspointers(ft.(*Type)) {
2905 continue
2906 }
2907 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2908 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2909 s.storeTypePtrs(ft.(*Type), addr, val)
2910 }
2911 default:
2912 s.Fatalf("bad write barrier type %s", t)
2913 }
2914}
2915
2916// do *left = right with a write barrier for all pointer parts of t.
2917func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
Keith Randall5ba31942016-01-25 17:06:54 -08002918 switch {
2919 case t.IsPtr() || t.IsMap() || t.IsChan():
2920 s.rtcall(writebarrierptr, true, nil, left, right)
2921 case t.IsString():
2922 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2923 s.rtcall(writebarrierptr, true, nil, left, ptr)
2924 case t.IsSlice():
2925 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2926 s.rtcall(writebarrierptr, true, nil, left, ptr)
2927 case t.IsInterface():
2928 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2929 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2930 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
Keith Randallaebf6612016-01-29 21:57:57 -08002931 case t.IsStruct():
2932 n := t.NumFields()
2933 for i := int64(0); i < n; i++ {
2934 ft := t.FieldType(i)
2935 if !haspointers(ft.(*Type)) {
2936 continue
2937 }
2938 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
2939 val := s.newValue1I(ssa.OpStructSelect, ft, i, right)
2940 s.storeTypePtrsWB(ft.(*Type), addr, val)
2941 }
Keith Randall5ba31942016-01-25 17:06:54 -08002942 default:
2943 s.Fatalf("bad write barrier type %s", t)
2944 }
Keith Randall9d22c102015-09-11 11:02:57 -07002945}
2946
Keith Randall5505e8c2015-09-12 23:27:26 -07002947// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2948// i,j,k may be nil, in which case they are set to their default value.
2949// t is a slice, ptr to array, or string type.
2950func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2951 var elemtype *Type
2952 var ptrtype *Type
2953 var ptr *ssa.Value
2954 var len *ssa.Value
2955 var cap *ssa.Value
2956 zero := s.constInt(Types[TINT], 0)
2957 switch {
2958 case t.IsSlice():
2959 elemtype = t.Type
2960 ptrtype = Ptrto(elemtype)
2961 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2962 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2963 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2964 case t.IsString():
2965 elemtype = Types[TUINT8]
2966 ptrtype = Ptrto(elemtype)
2967 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2968 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2969 cap = len
2970 case t.IsPtr():
2971 if !t.Type.IsArray() {
2972 s.Fatalf("bad ptr to array in slice %v\n", t)
2973 }
2974 elemtype = t.Type.Type
2975 ptrtype = Ptrto(elemtype)
2976 s.nilCheck(v)
2977 ptr = v
2978 len = s.constInt(Types[TINT], t.Type.Bound)
2979 cap = len
2980 default:
2981 s.Fatalf("bad type in slice %v\n", t)
2982 }
2983
2984 // Set default values
2985 if i == nil {
2986 i = zero
2987 }
2988 if j == nil {
2989 j = len
2990 }
2991 if k == nil {
2992 k = cap
2993 }
2994
2995 // Panic if slice indices are not in bounds.
2996 s.sliceBoundsCheck(i, j)
2997 if j != k {
2998 s.sliceBoundsCheck(j, k)
2999 }
3000 if k != cap {
3001 s.sliceBoundsCheck(k, cap)
3002 }
3003
3004 // Generate the following code assuming that indexes are in bounds.
3005 // The conditional is to make sure that we don't generate a slice
3006 // that points to the next object in memory.
Keith Randall582baae2015-11-02 21:28:13 -08003007 // rlen = (Sub64 j i)
3008 // rcap = (Sub64 k i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003009 // p = ptr
3010 // if rcap != 0 {
Keith Randall582baae2015-11-02 21:28:13 -08003011 // p = (AddPtr ptr (Mul64 low (Const64 size)))
Keith Randall5505e8c2015-09-12 23:27:26 -07003012 // }
3013 // result = (SliceMake p size)
Keith Randall582baae2015-11-02 21:28:13 -08003014 subOp := s.ssaOp(OSUB, Types[TINT])
3015 neqOp := s.ssaOp(ONE, Types[TINT])
3016 mulOp := s.ssaOp(OMUL, Types[TINT])
3017 rlen := s.newValue2(subOp, Types[TINT], j, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003018 var rcap *ssa.Value
3019 switch {
3020 case t.IsString():
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003021 // Capacity of the result is unimportant. However, we use
Keith Randall5505e8c2015-09-12 23:27:26 -07003022 // rcap to test if we've generated a zero-length slice.
3023 // Use length of strings for that.
3024 rcap = rlen
3025 case j == k:
3026 rcap = rlen
3027 default:
Keith Randall582baae2015-11-02 21:28:13 -08003028 rcap = s.newValue2(subOp, Types[TINT], k, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003029 }
3030
Keith Randallb32217a2015-09-17 16:45:10 -07003031 s.vars[&ptrVar] = ptr
Keith Randall5505e8c2015-09-12 23:27:26 -07003032
3033 // Generate code to test the resulting slice length.
Keith Randall582baae2015-11-02 21:28:13 -08003034 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
Keith Randall5505e8c2015-09-12 23:27:26 -07003035
3036 b := s.endBlock()
3037 b.Kind = ssa.BlockIf
3038 b.Likely = ssa.BranchLikely
3039 b.Control = cmp
3040
3041 // Generate code for non-zero length slice case.
3042 nz := s.f.NewBlock(ssa.BlockPlain)
3043 b.AddEdgeTo(nz)
3044 s.startBlock(nz)
3045 var inc *ssa.Value
3046 if elemtype.Width == 1 {
3047 inc = i
3048 } else {
Keith Randall582baae2015-11-02 21:28:13 -08003049 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
Keith Randall5505e8c2015-09-12 23:27:26 -07003050 }
Keith Randallb32217a2015-09-17 16:45:10 -07003051 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
Keith Randall5505e8c2015-09-12 23:27:26 -07003052 s.endBlock()
3053
3054 // All done.
3055 merge := s.f.NewBlock(ssa.BlockPlain)
3056 b.AddEdgeTo(merge)
3057 nz.AddEdgeTo(merge)
3058 s.startBlock(merge)
Keith Randallb32217a2015-09-17 16:45:10 -07003059 rptr := s.variable(&ptrVar, ptrtype)
3060 delete(s.vars, &ptrVar)
Keith Randall5505e8c2015-09-12 23:27:26 -07003061 return rptr, rlen, rcap
3062}
3063
David Chase42825882015-08-20 15:14:20 -04003064type u2fcvtTab struct {
3065 geq, cvt2F, and, rsh, or, add ssa.Op
3066 one func(*state, ssa.Type, int64) *ssa.Value
3067}
3068
3069var u64_f64 u2fcvtTab = u2fcvtTab{
3070 geq: ssa.OpGeq64,
3071 cvt2F: ssa.OpCvt64to64F,
3072 and: ssa.OpAnd64,
3073 rsh: ssa.OpRsh64Ux64,
3074 or: ssa.OpOr64,
3075 add: ssa.OpAdd64F,
3076 one: (*state).constInt64,
3077}
3078
3079var u64_f32 u2fcvtTab = u2fcvtTab{
3080 geq: ssa.OpGeq64,
3081 cvt2F: ssa.OpCvt64to32F,
3082 and: ssa.OpAnd64,
3083 rsh: ssa.OpRsh64Ux64,
3084 or: ssa.OpOr64,
3085 add: ssa.OpAdd32F,
3086 one: (*state).constInt64,
3087}
3088
3089// Excess generality on a machine with 64-bit integer registers.
3090// Not used on AMD64.
3091var u32_f32 u2fcvtTab = u2fcvtTab{
3092 geq: ssa.OpGeq32,
3093 cvt2F: ssa.OpCvt32to32F,
3094 and: ssa.OpAnd32,
3095 rsh: ssa.OpRsh32Ux32,
3096 or: ssa.OpOr32,
3097 add: ssa.OpAdd32F,
3098 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3099 return s.constInt32(t, int32(x))
3100 },
3101}
3102
3103func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3104 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3105}
3106
3107func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3108 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3109}
3110
3111func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3112 // if x >= 0 {
3113 // result = (floatY) x
3114 // } else {
3115 // y = uintX(x) ; y = x & 1
3116 // z = uintX(x) ; z = z >> 1
3117 // z = z >> 1
3118 // z = z | y
David Chase73151062015-08-26 14:25:40 -04003119 // result = floatY(z)
3120 // result = result + result
David Chase42825882015-08-20 15:14:20 -04003121 // }
3122 //
3123 // Code borrowed from old code generator.
3124 // What's going on: large 64-bit "unsigned" looks like
3125 // negative number to hardware's integer-to-float
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003126 // conversion. However, because the mantissa is only
David Chase42825882015-08-20 15:14:20 -04003127 // 63 bits, we don't need the LSB, so instead we do an
3128 // unsigned right shift (divide by two), convert, and
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003129 // double. However, before we do that, we need to be
David Chase42825882015-08-20 15:14:20 -04003130 // sure that we do not lose a "1" if that made the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003131 // difference in the resulting rounding. Therefore, we
3132 // preserve it, and OR (not ADD) it back in. The case
David Chase42825882015-08-20 15:14:20 -04003133 // that matters is when the eleven discarded bits are
3134 // equal to 10000000001; that rounds up, and the 1 cannot
3135 // be lost else it would round down if the LSB of the
3136 // candidate mantissa is 0.
3137 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3138 b := s.endBlock()
3139 b.Kind = ssa.BlockIf
3140 b.Control = cmp
3141 b.Likely = ssa.BranchLikely
3142
3143 bThen := s.f.NewBlock(ssa.BlockPlain)
3144 bElse := s.f.NewBlock(ssa.BlockPlain)
3145 bAfter := s.f.NewBlock(ssa.BlockPlain)
3146
Todd Neal47d67992015-08-28 21:36:29 -05003147 b.AddEdgeTo(bThen)
David Chase42825882015-08-20 15:14:20 -04003148 s.startBlock(bThen)
3149 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3150 s.vars[n] = a0
3151 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003152 bThen.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003153
Todd Neal47d67992015-08-28 21:36:29 -05003154 b.AddEdgeTo(bElse)
David Chase42825882015-08-20 15:14:20 -04003155 s.startBlock(bElse)
3156 one := cvttab.one(s, ft, 1)
3157 y := s.newValue2(cvttab.and, ft, x, one)
3158 z := s.newValue2(cvttab.rsh, ft, x, one)
3159 z = s.newValue2(cvttab.or, ft, z, y)
3160 a := s.newValue1(cvttab.cvt2F, tt, z)
3161 a1 := s.newValue2(cvttab.add, tt, a, a)
3162 s.vars[n] = a1
3163 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003164 bElse.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003165
3166 s.startBlock(bAfter)
3167 return s.variable(n, n.Type)
3168}
3169
Todd Neal707af252015-08-28 15:56:43 -05003170// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3171func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3172 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3173 s.Fatalf("node must be a map or a channel")
3174 }
Todd Neale0e40682015-08-26 18:40:52 -05003175 // if n == nil {
3176 // return 0
3177 // } else {
Todd Neal707af252015-08-28 15:56:43 -05003178 // // len
Todd Neale0e40682015-08-26 18:40:52 -05003179 // return *((*int)n)
Todd Neal707af252015-08-28 15:56:43 -05003180 // // cap
3181 // return *(((*int)n)+1)
Todd Neale0e40682015-08-26 18:40:52 -05003182 // }
3183 lenType := n.Type
Todd Neal67ac8a32015-08-28 15:20:54 -05003184 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
3185 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
Todd Neale0e40682015-08-26 18:40:52 -05003186 b := s.endBlock()
3187 b.Kind = ssa.BlockIf
3188 b.Control = cmp
3189 b.Likely = ssa.BranchUnlikely
3190
3191 bThen := s.f.NewBlock(ssa.BlockPlain)
3192 bElse := s.f.NewBlock(ssa.BlockPlain)
3193 bAfter := s.f.NewBlock(ssa.BlockPlain)
3194
Todd Neal707af252015-08-28 15:56:43 -05003195 // length/capacity of a nil map/chan is zero
Todd Neal47d67992015-08-28 21:36:29 -05003196 b.AddEdgeTo(bThen)
Todd Neale0e40682015-08-26 18:40:52 -05003197 s.startBlock(bThen)
3198 s.vars[n] = s.zeroVal(lenType)
3199 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003200 bThen.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003201
Todd Neal47d67992015-08-28 21:36:29 -05003202 b.AddEdgeTo(bElse)
Todd Neale0e40682015-08-26 18:40:52 -05003203 s.startBlock(bElse)
Todd Neal707af252015-08-28 15:56:43 -05003204 if n.Op == OLEN {
3205 // length is stored in the first word for map/chan
3206 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3207 } else if n.Op == OCAP {
3208 // capacity is stored in the second word for chan
3209 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3210 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3211 } else {
3212 s.Fatalf("op must be OLEN or OCAP")
3213 }
Todd Neale0e40682015-08-26 18:40:52 -05003214 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003215 bElse.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003216
3217 s.startBlock(bAfter)
3218 return s.variable(n, lenType)
3219}
3220
David Chase73151062015-08-26 14:25:40 -04003221type f2uCvtTab struct {
3222 ltf, cvt2U, subf ssa.Op
3223 value func(*state, ssa.Type, float64) *ssa.Value
3224}
3225
3226var f32_u64 f2uCvtTab = f2uCvtTab{
3227 ltf: ssa.OpLess32F,
3228 cvt2U: ssa.OpCvt32Fto64,
3229 subf: ssa.OpSub32F,
3230 value: (*state).constFloat32,
3231}
3232
3233var f64_u64 f2uCvtTab = f2uCvtTab{
3234 ltf: ssa.OpLess64F,
3235 cvt2U: ssa.OpCvt64Fto64,
3236 subf: ssa.OpSub64F,
3237 value: (*state).constFloat64,
3238}
3239
3240func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3241 return s.floatToUint(&f32_u64, n, x, ft, tt)
3242}
3243func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3244 return s.floatToUint(&f64_u64, n, x, ft, tt)
3245}
3246
3247func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3248 // if x < 9223372036854775808.0 {
3249 // result = uintY(x)
3250 // } else {
3251 // y = x - 9223372036854775808.0
3252 // z = uintY(y)
3253 // result = z | -9223372036854775808
3254 // }
3255 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3256 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3257 b := s.endBlock()
3258 b.Kind = ssa.BlockIf
3259 b.Control = cmp
3260 b.Likely = ssa.BranchLikely
3261
3262 bThen := s.f.NewBlock(ssa.BlockPlain)
3263 bElse := s.f.NewBlock(ssa.BlockPlain)
3264 bAfter := s.f.NewBlock(ssa.BlockPlain)
3265
Todd Neal47d67992015-08-28 21:36:29 -05003266 b.AddEdgeTo(bThen)
David Chase73151062015-08-26 14:25:40 -04003267 s.startBlock(bThen)
3268 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3269 s.vars[n] = a0
3270 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003271 bThen.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003272
Todd Neal47d67992015-08-28 21:36:29 -05003273 b.AddEdgeTo(bElse)
David Chase73151062015-08-26 14:25:40 -04003274 s.startBlock(bElse)
3275 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3276 y = s.newValue1(cvttab.cvt2U, tt, y)
3277 z := s.constInt64(tt, -9223372036854775808)
3278 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3279 s.vars[n] = a1
3280 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003281 bElse.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003282
3283 s.startBlock(bAfter)
3284 return s.variable(n, n.Type)
3285}
3286
Keith Randall269baa92015-09-17 10:31:16 -07003287// ifaceType returns the value for the word containing the type.
3288// n is the node for the interface expression.
3289// v is the corresponding value.
3290func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3291 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3292
3293 if isnilinter(n.Type) {
3294 // Have *eface. The type is the first word in the struct.
3295 return s.newValue1(ssa.OpITab, byteptr, v)
3296 }
3297
3298 // Have *iface.
3299 // The first word in the struct is the *itab.
3300 // If the *itab is nil, return 0.
3301 // Otherwise, the second word in the *itab is the type.
3302
3303 tab := s.newValue1(ssa.OpITab, byteptr, v)
3304 s.vars[&typVar] = tab
3305 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3306 b := s.endBlock()
3307 b.Kind = ssa.BlockIf
3308 b.Control = isnonnil
3309 b.Likely = ssa.BranchLikely
3310
3311 bLoad := s.f.NewBlock(ssa.BlockPlain)
3312 bEnd := s.f.NewBlock(ssa.BlockPlain)
3313
3314 b.AddEdgeTo(bLoad)
3315 b.AddEdgeTo(bEnd)
3316 bLoad.AddEdgeTo(bEnd)
3317
3318 s.startBlock(bLoad)
3319 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3320 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3321 s.endBlock()
3322
3323 s.startBlock(bEnd)
3324 typ := s.variable(&typVar, byteptr)
3325 delete(s.vars, &typVar)
3326 return typ
3327}
3328
3329// dottype generates SSA for a type assertion node.
3330// commaok indicates whether to panic or return a bool.
3331// If commaok is false, resok will be nil.
3332func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3333 iface := s.expr(n.Left)
3334 typ := s.ifaceType(n.Left, iface) // actual concrete type
3335 target := s.expr(typename(n.Type)) // target type
3336 if !isdirectiface(n.Type) {
3337 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3338 Fatalf("dottype needs a direct iface type %s", n.Type)
3339 }
3340
David Chase729abfa2015-10-26 17:34:06 -04003341 if Debug_typeassert > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003342 Warnl(n.Lineno, "type assertion inlined")
David Chase729abfa2015-10-26 17:34:06 -04003343 }
3344
Keith Randall269baa92015-09-17 10:31:16 -07003345 // TODO: If we have a nonempty interface and its itab field is nil,
3346 // then this test is redundant and ifaceType should just branch directly to bFail.
3347 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3348 b := s.endBlock()
3349 b.Kind = ssa.BlockIf
3350 b.Control = cond
3351 b.Likely = ssa.BranchLikely
3352
3353 byteptr := Ptrto(Types[TUINT8])
3354
3355 bOk := s.f.NewBlock(ssa.BlockPlain)
3356 bFail := s.f.NewBlock(ssa.BlockPlain)
3357 b.AddEdgeTo(bOk)
3358 b.AddEdgeTo(bFail)
3359
3360 if !commaok {
3361 // on failure, panic by calling panicdottype
3362 s.startBlock(bFail)
Keith Randall269baa92015-09-17 10:31:16 -07003363 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07003364 s.rtcall(panicdottype, false, nil, typ, target, taddr)
Keith Randall269baa92015-09-17 10:31:16 -07003365
3366 // on success, return idata field
3367 s.startBlock(bOk)
3368 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3369 }
3370
3371 // commaok is the more complicated case because we have
3372 // a control flow merge point.
3373 bEnd := s.f.NewBlock(ssa.BlockPlain)
3374
3375 // type assertion succeeded
3376 s.startBlock(bOk)
3377 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3378 s.vars[&okVar] = s.constBool(true)
3379 s.endBlock()
3380 bOk.AddEdgeTo(bEnd)
3381
3382 // type assertion failed
3383 s.startBlock(bFail)
3384 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3385 s.vars[&okVar] = s.constBool(false)
3386 s.endBlock()
3387 bFail.AddEdgeTo(bEnd)
3388
3389 // merge point
3390 s.startBlock(bEnd)
3391 res = s.variable(&idataVar, byteptr)
3392 resok = s.variable(&okVar, Types[TBOOL])
3393 delete(s.vars, &idataVar)
3394 delete(s.vars, &okVar)
3395 return res, resok
3396}
3397
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003398// checkgoto checks that a goto from from to to does not
3399// jump into a block or jump over variable declarations.
3400// It is a copy of checkgoto in the pre-SSA backend,
3401// modified only for line number handling.
3402// TODO: document how this works and why it is designed the way it is.
3403func (s *state) checkgoto(from *Node, to *Node) {
3404 if from.Sym == to.Sym {
3405 return
3406 }
3407
3408 nf := 0
3409 for fs := from.Sym; fs != nil; fs = fs.Link {
3410 nf++
3411 }
3412 nt := 0
3413 for fs := to.Sym; fs != nil; fs = fs.Link {
3414 nt++
3415 }
3416 fs := from.Sym
3417 for ; nf > nt; nf-- {
3418 fs = fs.Link
3419 }
3420 if fs != to.Sym {
3421 // decide what to complain about.
3422 // prefer to complain about 'into block' over declarations,
3423 // so scan backward to find most recent block or else dcl.
3424 var block *Sym
3425
3426 var dcl *Sym
3427 ts := to.Sym
3428 for ; nt > nf; nt-- {
3429 if ts.Pkg == nil {
3430 block = ts
3431 } else {
3432 dcl = ts
3433 }
3434 ts = ts.Link
3435 }
3436
3437 for ts != fs {
3438 if ts.Pkg == nil {
3439 block = ts
3440 } else {
3441 dcl = ts
3442 }
3443 ts = ts.Link
3444 fs = fs.Link
3445 }
3446
Robert Griesemerb83f3972016-03-02 11:01:25 -08003447 lno := from.Left.Lineno
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003448 if block != nil {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003449 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003450 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003451 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003452 }
3453 }
3454}
3455
Keith Randalld2fd43a2015-04-15 15:51:25 -07003456// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -07003457func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003458 v := s.vars[name]
3459 if v == nil {
Keith Randall8f22b522015-06-11 21:29:25 -07003460 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randallb5c5efd2016-01-14 16:02:23 -08003461 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003462 s.vars[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003463 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003464 }
3465 return v
3466}
3467
Keith Randallcfc2aa52015-05-18 16:44:20 -07003468func (s *state) mem() *ssa.Value {
Keith Randallb32217a2015-09-17 16:45:10 -07003469 return s.variable(&memVar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003470}
3471
Keith Randallcfc2aa52015-05-18 16:44:20 -07003472func (s *state) linkForwardReferences() {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003473 // Build SSA graph. Each variable on its first use in a basic block
Keith Randalld2fd43a2015-04-15 15:51:25 -07003474 // leaves a FwdRef in that block representing the incoming value
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003475 // of that variable. This function links that ref up with possible definitions,
3476 // inserting Phi values as needed. This is essentially the algorithm
Keith Randallb5c5efd2016-01-14 16:02:23 -08003477 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
Keith Randalld2fd43a2015-04-15 15:51:25 -07003478 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
Keith Randallb5c5efd2016-01-14 16:02:23 -08003479 // Differences:
3480 // - We use FwdRef nodes to postpone phi building until the CFG is
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003481 // completely built. That way we can avoid the notion of "sealed"
Keith Randallb5c5efd2016-01-14 16:02:23 -08003482 // blocks.
3483 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3484 for len(s.fwdRefs) > 0 {
3485 v := s.fwdRefs[len(s.fwdRefs)-1]
3486 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3487 s.resolveFwdRef(v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003488 }
3489}
3490
Keith Randallb5c5efd2016-01-14 16:02:23 -08003491// resolveFwdRef modifies v to be the variable's value at the start of its block.
3492// v must be a FwdRef op.
3493func (s *state) resolveFwdRef(v *ssa.Value) {
3494 b := v.Block
3495 name := v.Aux.(*Node)
3496 v.Aux = nil
Keith Randalld2fd43a2015-04-15 15:51:25 -07003497 if b == s.f.Entry {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003498 // Live variable at start of function.
Keith Randall6a8a9da2016-02-27 17:49:31 -08003499 if s.canSSA(name) {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003500 v.Op = ssa.OpArg
3501 v.Aux = name
3502 return
Keith Randall02f4d0a2015-11-02 08:10:26 -08003503 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003504 // Not SSAable. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -07003505 addr := s.decladdrs[name]
3506 if addr == nil {
3507 // TODO: closure args reach here.
David Chase32ffbf72015-10-08 17:14:12 -04003508 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
Keith Randall8c46aa52015-06-19 21:02:28 -07003509 }
3510 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3511 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3512 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003513 v.Op = ssa.OpLoad
3514 v.AddArgs(addr, s.startmem)
3515 return
Keith Randalld2fd43a2015-04-15 15:51:25 -07003516 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003517 if len(b.Preds) == 0 {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003518 // This block is dead; we have no predecessors and we're not the entry block.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003519 // It doesn't matter what we use here as long as it is well-formed.
3520 v.Op = ssa.OpUnknown
3521 return
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003522 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003523 // Find variable value on each predecessor.
3524 var argstore [4]*ssa.Value
3525 args := argstore[:0]
3526 for _, p := range b.Preds {
3527 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
Keith Randalld2fd43a2015-04-15 15:51:25 -07003528 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003529
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003530 // Decide if we need a phi or not. We need a phi if there
Keith Randallb5c5efd2016-01-14 16:02:23 -08003531 // are two different args (which are both not v).
3532 var w *ssa.Value
3533 for _, a := range args {
3534 if a == v {
3535 continue // self-reference
3536 }
3537 if a == w {
3538 continue // already have this witness
3539 }
3540 if w != nil {
3541 // two witnesses, need a phi value
3542 v.Op = ssa.OpPhi
3543 v.AddArgs(args...)
3544 return
3545 }
3546 w = a // save witness
3547 }
3548 if w == nil {
3549 s.Fatalf("no witness for reachable phi %s", v)
3550 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003551 // One witness. Make v a copy of w.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003552 v.Op = ssa.OpCopy
3553 v.AddArg(w)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003554}
3555
3556// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003557func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003558 m := s.defvars[b.ID]
3559 if v, ok := m[name]; ok {
3560 return v
3561 }
3562 // The variable is not defined by b and we haven't
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003563 // looked it up yet. Generate a FwdRef for the variable and return that.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003564 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3565 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003566 m[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003567 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003568 return v
3569}
3570
Keith Randallc24681a2015-10-22 14:22:38 -07003571func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3572 if n.Class == Pxxx {
3573 // Don't track our dummy nodes (&memVar etc.).
3574 return
3575 }
Keith Randallc24681a2015-10-22 14:22:38 -07003576 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3577 // Don't track autotmp_ variables.
3578 return
3579 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003580 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3581 // TODO: can't handle auto compound objects with pointers yet.
3582 // The live variable analysis barfs because we don't put VARDEF
3583 // pseudos in the right place when we spill to these nodes.
Keith Randallc24681a2015-10-22 14:22:38 -07003584 return
3585 }
3586 if n.Class == PAUTO && n.Xoffset != 0 {
3587 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3588 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003589 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3590 values, ok := s.f.NamedValues[loc]
Keith Randallc24681a2015-10-22 14:22:38 -07003591 if !ok {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003592 s.f.Names = append(s.f.Names, loc)
Keith Randallc24681a2015-10-22 14:22:38 -07003593 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003594 s.f.NamedValues[loc] = append(values, v)
Keith Randallc24681a2015-10-22 14:22:38 -07003595}
3596
Keith Randall083a6462015-05-12 11:06:44 -07003597// an unresolved branch
3598type branch struct {
3599 p *obj.Prog // branch instruction
3600 b *ssa.Block // target
3601}
3602
Keith Randall9569b952015-08-28 22:51:01 -07003603type genState struct {
3604 // branches remembers all the branch instructions we've seen
3605 // and where they would like to go.
3606 branches []branch
3607
3608 // bstart remembers where each block starts (indexed by block ID)
3609 bstart []*obj.Prog
3610
3611 // deferBranches remembers all the defer branches we've seen.
3612 deferBranches []*obj.Prog
3613
3614 // deferTarget remembers the (last) deferreturn call site.
3615 deferTarget *obj.Prog
3616}
3617
Keith Randall083a6462015-05-12 11:06:44 -07003618// genssa appends entries to ptxt for each instruction in f.
3619// gcargs and gclocals are filled in with pointer maps for the frame.
3620func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Keith Randall9569b952015-08-28 22:51:01 -07003621 var s genState
3622
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003623 e := f.Config.Frontend().(*ssaExport)
3624 // We're about to emit a bunch of Progs.
3625 // Since the only way to get here is to explicitly request it,
3626 // just fail on unimplemented instead of trying to unwind our mess.
3627 e.mustImplement = true
3628
Keith Randall083a6462015-05-12 11:06:44 -07003629 // Remember where each block starts.
Keith Randall9569b952015-08-28 22:51:01 -07003630 s.bstart = make([]*obj.Prog, f.NumBlocks())
Keith Randall083a6462015-05-12 11:06:44 -07003631
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003632 var valueProgs map[*obj.Prog]*ssa.Value
3633 var blockProgs map[*obj.Prog]*ssa.Block
3634 const logProgs = true
3635 if logProgs {
3636 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3637 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3638 f.Logf("genssa %s\n", f.Name)
3639 blockProgs[Pc] = f.Blocks[0]
3640 }
3641
Keith Randall083a6462015-05-12 11:06:44 -07003642 // Emit basic blocks
3643 for i, b := range f.Blocks {
Keith Randall9569b952015-08-28 22:51:01 -07003644 s.bstart[b.ID] = Pc
Keith Randall083a6462015-05-12 11:06:44 -07003645 // Emit values in block
Keith Randall7b773942016-01-22 13:44:58 -08003646 s.markMoves(b)
Keith Randall083a6462015-05-12 11:06:44 -07003647 for _, v := range b.Values {
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003648 x := Pc
Keith Randall9569b952015-08-28 22:51:01 -07003649 s.genValue(v)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003650 if logProgs {
3651 for ; x != Pc; x = x.Link {
3652 valueProgs[x] = v
3653 }
3654 }
Keith Randall083a6462015-05-12 11:06:44 -07003655 }
3656 // Emit control flow instructions for block
3657 var next *ssa.Block
Keith Randall91f69c62016-02-26 16:32:01 -08003658 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
Keith Randall8906d2a2016-02-22 23:19:00 -08003659 // If -N, leave next==nil so every block with successors
Keith Randall91f69c62016-02-26 16:32:01 -08003660 // ends in a JMP (except call blocks - plive doesn't like
3661 // select{send,recv} followed by a JMP call). Helps keep
3662 // line numbers for otherwise empty blocks.
Keith Randall083a6462015-05-12 11:06:44 -07003663 next = f.Blocks[i+1]
3664 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003665 x := Pc
Keith Randall9569b952015-08-28 22:51:01 -07003666 s.genBlock(b, next)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003667 if logProgs {
3668 for ; x != Pc; x = x.Link {
3669 blockProgs[x] = b
3670 }
3671 }
Keith Randall083a6462015-05-12 11:06:44 -07003672 }
3673
3674 // Resolve branches
Keith Randall9569b952015-08-28 22:51:01 -07003675 for _, br := range s.branches {
3676 br.p.To.Val = s.bstart[br.b.ID]
3677 }
Keith Randallca9e4502015-09-08 08:59:57 -07003678 if s.deferBranches != nil && s.deferTarget == nil {
3679 // This can happen when the function has a defer but
3680 // no return (because it has an infinite loop).
3681 s.deferReturn()
3682 Prog(obj.ARET)
3683 }
Keith Randall9569b952015-08-28 22:51:01 -07003684 for _, p := range s.deferBranches {
3685 p.To.Val = s.deferTarget
Keith Randall083a6462015-05-12 11:06:44 -07003686 }
3687
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003688 if logProgs {
3689 for p := ptxt; p != nil; p = p.Link {
3690 var s string
3691 if v, ok := valueProgs[p]; ok {
3692 s = v.String()
3693 } else if b, ok := blockProgs[p]; ok {
3694 s = b.String()
3695 } else {
3696 s = " " // most value and branch strings are 2-3 characters long
3697 }
3698 f.Logf("%s\t%s\n", s, p)
3699 }
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003700 if f.Config.HTML != nil {
3701 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3702 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3703 var buf bytes.Buffer
3704 buf.WriteString("<code>")
3705 buf.WriteString("<dl class=\"ssa-gen\">")
3706 for p := ptxt; p != nil; p = p.Link {
3707 buf.WriteString("<dt class=\"ssa-prog-src\">")
3708 if v, ok := valueProgs[p]; ok {
3709 buf.WriteString(v.HTML())
3710 } else if b, ok := blockProgs[p]; ok {
3711 buf.WriteString(b.HTML())
3712 }
3713 buf.WriteString("</dt>")
3714 buf.WriteString("<dd class=\"ssa-prog\">")
3715 buf.WriteString(html.EscapeString(p.String()))
3716 buf.WriteString("</dd>")
3717 buf.WriteString("</li>")
3718 }
3719 buf.WriteString("</dl>")
3720 buf.WriteString("</code>")
3721 f.Config.HTML.WriteColumn("genssa", buf.String())
3722 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3723 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003724 }
3725
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003726 // Emit static data
3727 if f.StaticData != nil {
3728 for _, n := range f.StaticData.([]*Node) {
3729 if !gen_as_init(n, false) {
Keith Randall0ec72b62015-09-08 15:42:53 -07003730 Fatalf("non-static data marked as static: %v\n\n", n, f)
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003731 }
3732 }
3733 }
3734
Keith Randalld2107fc2015-08-24 02:16:19 -07003735 // Allocate stack frame
3736 allocauto(ptxt)
Keith Randall083a6462015-05-12 11:06:44 -07003737
Keith Randalld2107fc2015-08-24 02:16:19 -07003738 // Generate gc bitmaps.
3739 liveness(Curfn, ptxt, gcargs, gclocals)
3740 gcsymdup(gcargs)
3741 gcsymdup(gclocals)
Keith Randall083a6462015-05-12 11:06:44 -07003742
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003743 // Add frame prologue. Zero ambiguously live variables.
Keith Randalld2107fc2015-08-24 02:16:19 -07003744 Thearch.Defframe(ptxt)
3745 if Debug['f'] != 0 {
3746 frame(0)
3747 }
3748
3749 // Remove leftover instrumentation from the instruction stream.
3750 removevardef(ptxt)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003751
3752 f.Config.HTML.Close()
Keith Randall083a6462015-05-12 11:06:44 -07003753}
3754
David Chase997a9f32015-08-12 16:38:11 -04003755// opregreg emits instructions for
David Chase8e601b22015-08-18 14:39:26 -04003756// dest := dest(To) op src(From)
David Chase997a9f32015-08-12 16:38:11 -04003757// and also returns the created obj.Prog so it
3758// may be further adjusted (offset, scale, etc).
3759func opregreg(op int, dest, src int16) *obj.Prog {
3760 p := Prog(op)
3761 p.From.Type = obj.TYPE_REG
3762 p.To.Type = obj.TYPE_REG
3763 p.To.Reg = dest
3764 p.From.Reg = src
3765 return p
3766}
3767
Keith Randall9569b952015-08-28 22:51:01 -07003768func (s *genState) genValue(v *ssa.Value) {
Michael Matloob81ccf502015-05-30 01:03:06 -04003769 lineno = v.Line
Keith Randall083a6462015-05-12 11:06:44 -07003770 switch v.Op {
Keith Randalla0da2d22016-02-04 15:08:47 -08003771 case ssa.OpAMD64ADDQ, ssa.OpAMD64ADDL, ssa.OpAMD64ADDW:
3772 r := regnum(v)
3773 r1 := regnum(v.Args[0])
3774 r2 := regnum(v.Args[1])
3775 switch {
3776 case r == r1:
3777 p := Prog(v.Op.Asm())
3778 p.From.Type = obj.TYPE_REG
3779 p.From.Reg = r2
3780 p.To.Type = obj.TYPE_REG
3781 p.To.Reg = r
3782 case r == r2:
3783 p := Prog(v.Op.Asm())
3784 p.From.Type = obj.TYPE_REG
3785 p.From.Reg = r1
3786 p.To.Type = obj.TYPE_REG
3787 p.To.Reg = r
3788 default:
3789 var asm int
3790 switch v.Op {
3791 case ssa.OpAMD64ADDQ:
3792 asm = x86.ALEAQ
3793 case ssa.OpAMD64ADDL:
3794 asm = x86.ALEAL
3795 case ssa.OpAMD64ADDW:
Ilya Tocare96b2322016-02-15 17:01:26 +03003796 asm = x86.ALEAL
Keith Randalla0da2d22016-02-04 15:08:47 -08003797 }
3798 p := Prog(asm)
3799 p.From.Type = obj.TYPE_MEM
3800 p.From.Reg = r1
3801 p.From.Scale = 1
3802 p.From.Index = r2
3803 p.To.Type = obj.TYPE_REG
3804 p.To.Reg = r
3805 }
Keith Randall20550cb2015-07-28 16:04:50 -07003806 // 2-address opcode arithmetic, symmetric
David Chase997a9f32015-08-12 16:38:11 -04003807 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02003808 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
Keith Randall20550cb2015-07-28 16:04:50 -07003809 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3810 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
David Chase997a9f32015-08-12 16:38:11 -04003811 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
David Chase3a9d0ac2015-08-28 14:24:10 -04003812 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
Michael Matloob73054f52015-06-14 11:38:46 -07003813 r := regnum(v)
3814 x := regnum(v.Args[0])
3815 y := regnum(v.Args[1])
3816 if x != r && y != r {
Keith Randall90065ea2016-01-15 08:45:47 -08003817 opregreg(moveByType(v.Type), r, x)
Michael Matloob73054f52015-06-14 11:38:46 -07003818 x = r
3819 }
3820 p := Prog(v.Op.Asm())
3821 p.From.Type = obj.TYPE_REG
3822 p.To.Type = obj.TYPE_REG
3823 p.To.Reg = r
3824 if x == r {
3825 p.From.Reg = y
3826 } else {
3827 p.From.Reg = x
3828 }
Keith Randall20550cb2015-07-28 16:04:50 -07003829 // 2-address opcode arithmetic, not symmetric
3830 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
Keith Randallbe1eb572015-07-22 13:46:15 -07003831 r := regnum(v)
3832 x := regnum(v.Args[0])
Keith Randall20550cb2015-07-28 16:04:50 -07003833 y := regnum(v.Args[1])
3834 var neg bool
3835 if y == r {
3836 // compute -(y-x) instead
3837 x, y = y, x
3838 neg = true
Keith Randallbe1eb572015-07-22 13:46:15 -07003839 }
Keith Randall083a6462015-05-12 11:06:44 -07003840 if x != r {
Keith Randall90065ea2016-01-15 08:45:47 -08003841 opregreg(moveByType(v.Type), r, x)
Keith Randall083a6462015-05-12 11:06:44 -07003842 }
David Chase997a9f32015-08-12 16:38:11 -04003843 opregreg(v.Op.Asm(), r, y)
Keith Randall20550cb2015-07-28 16:04:50 -07003844
Keith Randall20550cb2015-07-28 16:04:50 -07003845 if neg {
Ilya Tocare96b2322016-02-15 17:01:26 +03003846 if v.Op == ssa.OpAMD64SUBQ {
3847 p := Prog(x86.ANEGQ)
3848 p.To.Type = obj.TYPE_REG
3849 p.To.Reg = r
3850 } else { // Avoids partial registers write
3851 p := Prog(x86.ANEGL)
3852 p.To.Type = obj.TYPE_REG
3853 p.To.Reg = r
3854 }
Keith Randall20550cb2015-07-28 16:04:50 -07003855 }
David Chase997a9f32015-08-12 16:38:11 -04003856 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3857 r := regnum(v)
3858 x := regnum(v.Args[0])
3859 y := regnum(v.Args[1])
3860 if y == r && x != r {
3861 // r/y := x op r/y, need to preserve x and rewrite to
3862 // r/y := r/y op x15
3863 x15 := int16(x86.REG_X15)
3864 // register move y to x15
3865 // register move x to y
3866 // rename y with x15
Keith Randall90065ea2016-01-15 08:45:47 -08003867 opregreg(moveByType(v.Type), x15, y)
3868 opregreg(moveByType(v.Type), r, x)
David Chase997a9f32015-08-12 16:38:11 -04003869 y = x15
3870 } else if x != r {
Keith Randall90065ea2016-01-15 08:45:47 -08003871 opregreg(moveByType(v.Type), r, x)
David Chase997a9f32015-08-12 16:38:11 -04003872 }
3873 opregreg(v.Op.Asm(), r, y)
3874
Todd Neala45f2d82015-08-17 17:46:06 -05003875 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
Todd Neal57d9e7e2015-08-18 19:51:44 -05003876 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3877 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3878 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
Todd Neala45f2d82015-08-17 17:46:06 -05003879
3880 // Arg[0] is already in AX as it's the only register we allow
3881 // and AX is the only output
3882 x := regnum(v.Args[1])
3883
3884 // CPU faults upon signed overflow, which occurs when most
Todd Neal57d9e7e2015-08-18 19:51:44 -05003885 // negative int is divided by -1.
Todd Neala45f2d82015-08-17 17:46:06 -05003886 var j *obj.Prog
3887 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
Todd Neal57d9e7e2015-08-18 19:51:44 -05003888 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3889 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
Todd Neala45f2d82015-08-17 17:46:06 -05003890
3891 var c *obj.Prog
3892 switch v.Op {
Todd Neal57d9e7e2015-08-18 19:51:44 -05003893 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
Todd Neala45f2d82015-08-17 17:46:06 -05003894 c = Prog(x86.ACMPQ)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003895 j = Prog(x86.AJEQ)
3896 // go ahead and sign extend to save doing it later
3897 Prog(x86.ACQO)
3898
3899 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
Todd Neala45f2d82015-08-17 17:46:06 -05003900 c = Prog(x86.ACMPL)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003901 j = Prog(x86.AJEQ)
3902 Prog(x86.ACDQ)
3903
3904 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
Todd Neala45f2d82015-08-17 17:46:06 -05003905 c = Prog(x86.ACMPW)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003906 j = Prog(x86.AJEQ)
3907 Prog(x86.ACWD)
Todd Neala45f2d82015-08-17 17:46:06 -05003908 }
3909 c.From.Type = obj.TYPE_REG
3910 c.From.Reg = x
3911 c.To.Type = obj.TYPE_CONST
3912 c.To.Offset = -1
3913
Todd Neala45f2d82015-08-17 17:46:06 -05003914 j.To.Type = obj.TYPE_BRANCH
3915
3916 }
3917
Todd Neal57d9e7e2015-08-18 19:51:44 -05003918 // for unsigned ints, we sign extend by setting DX = 0
3919 // signed ints were sign extended above
3920 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3921 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3922 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
Todd Neala45f2d82015-08-17 17:46:06 -05003923 c := Prog(x86.AXORQ)
3924 c.From.Type = obj.TYPE_REG
3925 c.From.Reg = x86.REG_DX
3926 c.To.Type = obj.TYPE_REG
3927 c.To.Reg = x86.REG_DX
Todd Neala45f2d82015-08-17 17:46:06 -05003928 }
3929
3930 p := Prog(v.Op.Asm())
3931 p.From.Type = obj.TYPE_REG
3932 p.From.Reg = x
3933
3934 // signed division, rest of the check for -1 case
3935 if j != nil {
3936 j2 := Prog(obj.AJMP)
3937 j2.To.Type = obj.TYPE_BRANCH
3938
Todd Neal57d9e7e2015-08-18 19:51:44 -05003939 var n *obj.Prog
3940 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3941 v.Op == ssa.OpAMD64DIVW {
3942 // n * -1 = -n
3943 n = Prog(x86.ANEGQ)
3944 n.To.Type = obj.TYPE_REG
3945 n.To.Reg = x86.REG_AX
3946 } else {
3947 // n % -1 == 0
3948 n = Prog(x86.AXORQ)
3949 n.From.Type = obj.TYPE_REG
3950 n.From.Reg = x86.REG_DX
3951 n.To.Type = obj.TYPE_REG
3952 n.To.Reg = x86.REG_DX
3953 }
Todd Neala45f2d82015-08-17 17:46:06 -05003954
3955 j.To.Val = n
3956 j2.To.Val = Pc
3957 }
3958
Keith Randalla3055af2016-02-05 20:26:18 -08003959 case ssa.OpAMD64HMULQ, ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3960 ssa.OpAMD64HMULQU, ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
Todd Neal67cbd5b2015-08-18 19:14:47 -05003961 // the frontend rewrites constant division by 8/16/32 bit integers into
3962 // HMUL by a constant
Keith Randalla3055af2016-02-05 20:26:18 -08003963 // SSA rewrites generate the 64 bit versions
Todd Neal67cbd5b2015-08-18 19:14:47 -05003964
3965 // Arg[0] is already in AX as it's the only register we allow
3966 // and DX is the only output we care about (the high bits)
3967 p := Prog(v.Op.Asm())
3968 p.From.Type = obj.TYPE_REG
3969 p.From.Reg = regnum(v.Args[1])
3970
3971 // IMULB puts the high portion in AH instead of DL,
3972 // so move it to DL for consistency
3973 if v.Type.Size() == 1 {
3974 m := Prog(x86.AMOVB)
3975 m.From.Type = obj.TYPE_REG
3976 m.From.Reg = x86.REG_AH
3977 m.To.Type = obj.TYPE_REG
3978 m.To.Reg = x86.REG_DX
3979 }
3980
Keith Randalla3055af2016-02-05 20:26:18 -08003981 case ssa.OpAMD64AVGQU:
3982 // compute (x+y)/2 unsigned.
3983 // Do a 64-bit add, the overflow goes into the carry.
3984 // Shift right once and pull the carry back into the 63rd bit.
3985 r := regnum(v)
3986 x := regnum(v.Args[0])
3987 y := regnum(v.Args[1])
3988 if x != r && y != r {
3989 opregreg(moveByType(v.Type), r, x)
3990 x = r
3991 }
3992 p := Prog(x86.AADDQ)
3993 p.From.Type = obj.TYPE_REG
3994 p.To.Type = obj.TYPE_REG
3995 p.To.Reg = r
3996 if x == r {
3997 p.From.Reg = y
3998 } else {
3999 p.From.Reg = x
4000 }
4001 p = Prog(x86.ARCRQ)
4002 p.From.Type = obj.TYPE_CONST
4003 p.From.Offset = 1
4004 p.To.Type = obj.TYPE_REG
4005 p.To.Reg = r
4006
Keith Randall20550cb2015-07-28 16:04:50 -07004007 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
4008 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
4009 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
Keith Randall6f188472015-06-10 10:39:57 -07004010 x := regnum(v.Args[0])
4011 r := regnum(v)
4012 if x != r {
4013 if r == x86.REG_CX {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004014 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
Keith Randall6f188472015-06-10 10:39:57 -07004015 }
Keith Randall90065ea2016-01-15 08:45:47 -08004016 p := Prog(moveByType(v.Type))
Keith Randall6f188472015-06-10 10:39:57 -07004017 p.From.Type = obj.TYPE_REG
4018 p.From.Reg = x
4019 p.To.Type = obj.TYPE_REG
4020 p.To.Reg = r
Keith Randall6f188472015-06-10 10:39:57 -07004021 }
Michael Matloob703ef062015-06-16 11:11:16 -07004022 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -07004023 p.From.Type = obj.TYPE_REG
4024 p.From.Reg = regnum(v.Args[1]) // should be CX
4025 p.To.Type = obj.TYPE_REG
4026 p.To.Reg = r
Keith Randall20550cb2015-07-28 16:04:50 -07004027 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
Keith Randalla0da2d22016-02-04 15:08:47 -08004028 r := regnum(v)
4029 a := regnum(v.Args[0])
4030 if r == a {
Todd Nealc17b6b42016-02-19 16:58:21 -06004031 if v.AuxInt2Int64() == 1 {
Ilya Tocare93410d2016-02-05 19:24:53 +03004032 var asm int
4033 switch v.Op {
4034 // Software optimization manual recommends add $1,reg.
4035 // But inc/dec is 1 byte smaller. ICC always uses inc
4036 // Clang/GCC choose depending on flags, but prefer add.
4037 // Experiments show that inc/dec is both a little faster
4038 // and make a binary a little smaller.
4039 case ssa.OpAMD64ADDQconst:
4040 asm = x86.AINCQ
4041 case ssa.OpAMD64ADDLconst:
4042 asm = x86.AINCL
4043 case ssa.OpAMD64ADDWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004044 asm = x86.AINCL
Ilya Tocare93410d2016-02-05 19:24:53 +03004045 }
4046 p := Prog(asm)
4047 p.To.Type = obj.TYPE_REG
4048 p.To.Reg = r
4049 return
Todd Nealc17b6b42016-02-19 16:58:21 -06004050 } else if v.AuxInt2Int64() == -1 {
Ilya Tocare93410d2016-02-05 19:24:53 +03004051 var asm int
4052 switch v.Op {
4053 case ssa.OpAMD64ADDQconst:
4054 asm = x86.ADECQ
4055 case ssa.OpAMD64ADDLconst:
4056 asm = x86.ADECL
4057 case ssa.OpAMD64ADDWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004058 asm = x86.ADECL
Ilya Tocare93410d2016-02-05 19:24:53 +03004059 }
4060 p := Prog(asm)
4061 p.To.Type = obj.TYPE_REG
4062 p.To.Reg = r
4063 return
4064 } else {
4065 p := Prog(v.Op.Asm())
4066 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004067 p.From.Offset = v.AuxInt2Int64()
Ilya Tocare93410d2016-02-05 19:24:53 +03004068 p.To.Type = obj.TYPE_REG
4069 p.To.Reg = r
4070 return
4071 }
Keith Randalla0da2d22016-02-04 15:08:47 -08004072 }
Keith Randall20550cb2015-07-28 16:04:50 -07004073 var asm int
4074 switch v.Op {
4075 case ssa.OpAMD64ADDQconst:
4076 asm = x86.ALEAQ
4077 case ssa.OpAMD64ADDLconst:
4078 asm = x86.ALEAL
4079 case ssa.OpAMD64ADDWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004080 asm = x86.ALEAL
Keith Randall20550cb2015-07-28 16:04:50 -07004081 }
4082 p := Prog(asm)
4083 p.From.Type = obj.TYPE_MEM
Keith Randalla0da2d22016-02-04 15:08:47 -08004084 p.From.Reg = a
Todd Nealc17b6b42016-02-19 16:58:21 -06004085 p.From.Offset = v.AuxInt2Int64()
Keith Randall20550cb2015-07-28 16:04:50 -07004086 p.To.Type = obj.TYPE_REG
Keith Randalla0da2d22016-02-04 15:08:47 -08004087 p.To.Reg = r
Alexandru Moșoi7a6de6d2015-08-14 13:23:11 +02004088 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
Keith Randall20550cb2015-07-28 16:04:50 -07004089 r := regnum(v)
4090 x := regnum(v.Args[0])
4091 if r != x {
Keith Randall90065ea2016-01-15 08:45:47 -08004092 p := Prog(moveByType(v.Type))
Keith Randall20550cb2015-07-28 16:04:50 -07004093 p.From.Type = obj.TYPE_REG
4094 p.From.Reg = x
4095 p.To.Type = obj.TYPE_REG
4096 p.To.Reg = r
4097 }
4098 p := Prog(v.Op.Asm())
4099 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004100 p.From.Offset = v.AuxInt2Int64()
Keith Randall20550cb2015-07-28 16:04:50 -07004101 p.To.Type = obj.TYPE_REG
4102 p.To.Reg = r
4103 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
4104 // instead of using the MOVQ above.
4105 //p.From3 = new(obj.Addr)
4106 //p.From3.Type = obj.TYPE_REG
4107 //p.From3.Reg = regnum(v.Args[0])
Ilya Tocare93410d2016-02-05 19:24:53 +03004108 case ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst:
4109 x := regnum(v.Args[0])
4110 r := regnum(v)
4111 // We have 3-op add (lea), so transforming a = b - const into
4112 // a = b + (- const), saves us 1 instruction. We can't fit
4113 // - (-1 << 31) into 4 bytes offset in lea.
4114 // We handle 2-address just fine below.
Todd Nealc17b6b42016-02-19 16:58:21 -06004115 if v.AuxInt2Int64() == -1<<31 || x == r {
Ilya Tocare93410d2016-02-05 19:24:53 +03004116 if x != r {
4117 // This code compensates for the fact that the register allocator
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004118 // doesn't understand 2-address instructions yet. TODO: fix that.
Ilya Tocare93410d2016-02-05 19:24:53 +03004119 p := Prog(moveByType(v.Type))
4120 p.From.Type = obj.TYPE_REG
4121 p.From.Reg = x
4122 p.To.Type = obj.TYPE_REG
4123 p.To.Reg = r
4124 }
4125 p := Prog(v.Op.Asm())
4126 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004127 p.From.Offset = v.AuxInt2Int64()
Ilya Tocare93410d2016-02-05 19:24:53 +03004128 p.To.Type = obj.TYPE_REG
4129 p.To.Reg = r
Todd Nealc17b6b42016-02-19 16:58:21 -06004130 } else if x == r && v.AuxInt2Int64() == -1 {
Ilya Tocare93410d2016-02-05 19:24:53 +03004131 var asm int
4132 // x = x - (-1) is the same as x++
4133 // See OpAMD64ADDQconst comments about inc vs add $1,reg
4134 switch v.Op {
4135 case ssa.OpAMD64SUBQconst:
4136 asm = x86.AINCQ
4137 case ssa.OpAMD64SUBLconst:
4138 asm = x86.AINCL
4139 case ssa.OpAMD64SUBWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004140 asm = x86.AINCL
Ilya Tocare93410d2016-02-05 19:24:53 +03004141 }
4142 p := Prog(asm)
4143 p.To.Type = obj.TYPE_REG
4144 p.To.Reg = r
Todd Nealc17b6b42016-02-19 16:58:21 -06004145 } else if x == r && v.AuxInt2Int64() == 1 {
Ilya Tocare93410d2016-02-05 19:24:53 +03004146 var asm int
4147 switch v.Op {
4148 case ssa.OpAMD64SUBQconst:
4149 asm = x86.ADECQ
4150 case ssa.OpAMD64SUBLconst:
4151 asm = x86.ADECL
4152 case ssa.OpAMD64SUBWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004153 asm = x86.ADECL
Ilya Tocare93410d2016-02-05 19:24:53 +03004154 }
4155 p := Prog(asm)
4156 p.To.Type = obj.TYPE_REG
4157 p.To.Reg = r
4158 } else {
4159 var asm int
4160 switch v.Op {
4161 case ssa.OpAMD64SUBQconst:
4162 asm = x86.ALEAQ
4163 case ssa.OpAMD64SUBLconst:
4164 asm = x86.ALEAL
4165 case ssa.OpAMD64SUBWconst:
Ilya Tocare96b2322016-02-15 17:01:26 +03004166 asm = x86.ALEAL
Ilya Tocare93410d2016-02-05 19:24:53 +03004167 }
4168 p := Prog(asm)
4169 p.From.Type = obj.TYPE_MEM
4170 p.From.Reg = x
Todd Nealc17b6b42016-02-19 16:58:21 -06004171 p.From.Offset = -v.AuxInt2Int64()
Ilya Tocare93410d2016-02-05 19:24:53 +03004172 p.To.Type = obj.TYPE_REG
4173 p.To.Reg = r
4174 }
4175
Keith Randall20550cb2015-07-28 16:04:50 -07004176 case ssa.OpAMD64ADDBconst,
4177 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
4178 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
4179 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
Ilya Tocare93410d2016-02-05 19:24:53 +03004180 ssa.OpAMD64SUBBconst, ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst,
4181 ssa.OpAMD64SHLBconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst,
4182 ssa.OpAMD64SHRBconst, ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst,
4183 ssa.OpAMD64SARBconst, ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst,
4184 ssa.OpAMD64ROLBconst:
Keith Randall20550cb2015-07-28 16:04:50 -07004185 // This code compensates for the fact that the register allocator
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004186 // doesn't understand 2-address instructions yet. TODO: fix that.
Keith Randall247786c2015-05-28 10:47:24 -07004187 x := regnum(v.Args[0])
4188 r := regnum(v)
4189 if x != r {
Keith Randall90065ea2016-01-15 08:45:47 -08004190 p := Prog(moveByType(v.Type))
Keith Randall247786c2015-05-28 10:47:24 -07004191 p.From.Type = obj.TYPE_REG
4192 p.From.Reg = x
4193 p.To.Type = obj.TYPE_REG
4194 p.To.Reg = r
Keith Randall247786c2015-05-28 10:47:24 -07004195 }
Michael Matloob703ef062015-06-16 11:11:16 -07004196 p := Prog(v.Op.Asm())
Keith Randall247786c2015-05-28 10:47:24 -07004197 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004198 p.From.Offset = v.AuxInt2Int64()
Keith Randall247786c2015-05-28 10:47:24 -07004199 p.To.Type = obj.TYPE_REG
Keith Randalldbd83c42015-06-28 06:08:50 -07004200 p.To.Reg = r
Keith Randall4b803152015-07-29 17:07:09 -07004201 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
Keith Randall6f188472015-06-10 10:39:57 -07004202 r := regnum(v)
Keith Randall20550cb2015-07-28 16:04:50 -07004203 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -07004204 p.From.Type = obj.TYPE_REG
4205 p.From.Reg = r
4206 p.To.Type = obj.TYPE_REG
4207 p.To.Reg = r
Todd Neald90e0482015-07-23 20:01:40 -05004208 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
Keith Randall247786c2015-05-28 10:47:24 -07004209 p := Prog(x86.ALEAQ)
4210 p.From.Type = obj.TYPE_MEM
4211 p.From.Reg = regnum(v.Args[0])
Todd Neald90e0482015-07-23 20:01:40 -05004212 switch v.Op {
4213 case ssa.OpAMD64LEAQ1:
4214 p.From.Scale = 1
4215 case ssa.OpAMD64LEAQ2:
4216 p.From.Scale = 2
4217 case ssa.OpAMD64LEAQ4:
4218 p.From.Scale = 4
4219 case ssa.OpAMD64LEAQ8:
4220 p.From.Scale = 8
4221 }
Keith Randall247786c2015-05-28 10:47:24 -07004222 p.From.Index = regnum(v.Args[1])
Keith Randall8c46aa52015-06-19 21:02:28 -07004223 addAux(&p.From, v)
4224 p.To.Type = obj.TYPE_REG
4225 p.To.Reg = regnum(v)
4226 case ssa.OpAMD64LEAQ:
4227 p := Prog(x86.ALEAQ)
4228 p.From.Type = obj.TYPE_MEM
4229 p.From.Reg = regnum(v.Args[0])
4230 addAux(&p.From, v)
Keith Randall247786c2015-05-28 10:47:24 -07004231 p.To.Type = obj.TYPE_REG
4232 p.To.Reg = regnum(v)
Keith Randall20550cb2015-07-28 16:04:50 -07004233 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
4234 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
David Chase8e601b22015-08-18 14:39:26 -04004235 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
4236 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
4237 // Go assembler has swapped operands for UCOMISx relative to CMP,
4238 // must account for that right here.
4239 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
Keith Randall1cc57892016-01-30 11:25:38 -08004240 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst:
Keith Randall20550cb2015-07-28 16:04:50 -07004241 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07004242 p.From.Type = obj.TYPE_REG
4243 p.From.Reg = regnum(v.Args[0])
4244 p.To.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004245 p.To.Offset = v.AuxInt2Int64()
Keith Randall1cc57892016-01-30 11:25:38 -08004246 case ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
4247 p := Prog(v.Op.Asm())
4248 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004249 p.From.Offset = v.AuxInt2Int64()
Keith Randall1cc57892016-01-30 11:25:38 -08004250 p.To.Type = obj.TYPE_REG
4251 p.To.Reg = regnum(v.Args[0])
Keith Randall9cb332e2015-07-28 14:19:20 -07004252 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
Keith Randall083a6462015-05-12 11:06:44 -07004253 x := regnum(v)
Keith Randall9cb332e2015-07-28 14:19:20 -07004254 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07004255 p.From.Type = obj.TYPE_CONST
Todd Nealc17b6b42016-02-19 16:58:21 -06004256 p.From.Offset = v.AuxInt2Int64()
Keith Randall083a6462015-05-12 11:06:44 -07004257 p.To.Type = obj.TYPE_REG
4258 p.To.Reg = x
Keith Randall7b773942016-01-22 13:44:58 -08004259 // If flags are live at this instruction, suppress the
4260 // MOV $0,AX -> XOR AX,AX optimization.
4261 if v.Aux != nil {
4262 p.Mark |= x86.PRESERVEFLAGS
4263 }
David Chase997a9f32015-08-12 16:38:11 -04004264 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
4265 x := regnum(v)
4266 p := Prog(v.Op.Asm())
4267 p.From.Type = obj.TYPE_FCONST
Todd Neal19447a62015-09-04 06:33:56 -05004268 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
David Chase997a9f32015-08-12 16:38:11 -04004269 p.To.Type = obj.TYPE_REG
4270 p.To.Reg = x
Keith Randall1cc57892016-01-30 11:25:38 -08004271 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:
Michael Matloob703ef062015-06-16 11:11:16 -07004272 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07004273 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07004274 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07004275 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004276 p.To.Type = obj.TYPE_REG
4277 p.To.Reg = regnum(v)
David Chase997a9f32015-08-12 16:38:11 -04004278 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
4279 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07004280 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07004281 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07004282 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004283 p.From.Scale = 8
4284 p.From.Index = regnum(v.Args[1])
4285 p.To.Type = obj.TYPE_REG
4286 p.To.Reg = regnum(v)
Keith Randall9278a042016-02-02 11:13:50 -08004287 case ssa.OpAMD64MOVLloadidx4, ssa.OpAMD64MOVSSloadidx4:
David Chase997a9f32015-08-12 16:38:11 -04004288 p := Prog(v.Op.Asm())
4289 p.From.Type = obj.TYPE_MEM
4290 p.From.Reg = regnum(v.Args[0])
4291 addAux(&p.From, v)
4292 p.From.Scale = 4
4293 p.From.Index = regnum(v.Args[1])
4294 p.To.Type = obj.TYPE_REG
4295 p.To.Reg = regnum(v)
Keith Randall9278a042016-02-02 11:13:50 -08004296 case ssa.OpAMD64MOVWloadidx2:
4297 p := Prog(v.Op.Asm())
4298 p.From.Type = obj.TYPE_MEM
4299 p.From.Reg = regnum(v.Args[0])
4300 addAux(&p.From, v)
4301 p.From.Scale = 2
4302 p.From.Index = regnum(v.Args[1])
4303 p.To.Type = obj.TYPE_REG
4304 p.To.Reg = regnum(v)
4305 case ssa.OpAMD64MOVBloadidx1:
4306 p := Prog(v.Op.Asm())
4307 p.From.Type = obj.TYPE_MEM
4308 p.From.Reg = regnum(v.Args[0])
4309 addAux(&p.From, v)
4310 p.From.Scale = 1
4311 p.From.Index = regnum(v.Args[1])
4312 p.To.Type = obj.TYPE_REG
4313 p.To.Reg = regnum(v)
Keith Randall10462eb2015-10-21 17:18:07 -07004314 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
Michael Matloob73054f52015-06-14 11:38:46 -07004315 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07004316 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07004317 p.From.Reg = regnum(v.Args[1])
Keith Randall083a6462015-05-12 11:06:44 -07004318 p.To.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07004319 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07004320 addAux(&p.To, v)
David Chase997a9f32015-08-12 16:38:11 -04004321 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
4322 p := Prog(v.Op.Asm())
Josh Bleecher Snyder3e3d1622015-07-27 16:36:36 -07004323 p.From.Type = obj.TYPE_REG
4324 p.From.Reg = regnum(v.Args[2])
4325 p.To.Type = obj.TYPE_MEM
4326 p.To.Reg = regnum(v.Args[0])
4327 p.To.Scale = 8
4328 p.To.Index = regnum(v.Args[1])
4329 addAux(&p.To, v)
Keith Randall1cc57892016-01-30 11:25:38 -08004330 case ssa.OpAMD64MOVSSstoreidx4, ssa.OpAMD64MOVLstoreidx4:
David Chase997a9f32015-08-12 16:38:11 -04004331 p := Prog(v.Op.Asm())
4332 p.From.Type = obj.TYPE_REG
4333 p.From.Reg = regnum(v.Args[2])
4334 p.To.Type = obj.TYPE_MEM
4335 p.To.Reg = regnum(v.Args[0])
4336 p.To.Scale = 4
4337 p.To.Index = regnum(v.Args[1])
4338 addAux(&p.To, v)
Keith Randall1cc57892016-01-30 11:25:38 -08004339 case ssa.OpAMD64MOVWstoreidx2:
4340 p := Prog(v.Op.Asm())
4341 p.From.Type = obj.TYPE_REG
4342 p.From.Reg = regnum(v.Args[2])
4343 p.To.Type = obj.TYPE_MEM
4344 p.To.Reg = regnum(v.Args[0])
4345 p.To.Scale = 2
4346 p.To.Index = regnum(v.Args[1])
4347 addAux(&p.To, v)
4348 case ssa.OpAMD64MOVBstoreidx1:
4349 p := Prog(v.Op.Asm())
4350 p.From.Type = obj.TYPE_REG
4351 p.From.Reg = regnum(v.Args[2])
4352 p.To.Type = obj.TYPE_MEM
4353 p.To.Reg = regnum(v.Args[0])
4354 p.To.Scale = 1
4355 p.To.Index = regnum(v.Args[1])
4356 addAux(&p.To, v)
Keith Randalld43f2e32015-10-21 13:13:56 -07004357 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4358 p := Prog(v.Op.Asm())
4359 p.From.Type = obj.TYPE_CONST
Keith Randall16b1fce2016-01-31 11:39:39 -08004360 sc := v.AuxValAndOff()
Keith Randalld43f2e32015-10-21 13:13:56 -07004361 i := sc.Val()
4362 switch v.Op {
4363 case ssa.OpAMD64MOVBstoreconst:
4364 i = int64(int8(i))
4365 case ssa.OpAMD64MOVWstoreconst:
4366 i = int64(int16(i))
4367 case ssa.OpAMD64MOVLstoreconst:
4368 i = int64(int32(i))
4369 case ssa.OpAMD64MOVQstoreconst:
4370 }
4371 p.From.Offset = i
4372 p.To.Type = obj.TYPE_MEM
4373 p.To.Reg = regnum(v.Args[0])
4374 addAux2(&p.To, v, sc.Off())
Keith Randalla6fb5142016-02-04 15:53:33 -08004375 case ssa.OpAMD64MOVQstoreconstidx8, ssa.OpAMD64MOVLstoreconstidx4, ssa.OpAMD64MOVWstoreconstidx2, ssa.OpAMD64MOVBstoreconstidx1:
4376 p := Prog(v.Op.Asm())
4377 p.From.Type = obj.TYPE_CONST
4378 sc := v.AuxValAndOff()
4379 switch v.Op {
4380 case ssa.OpAMD64MOVBstoreconstidx1:
4381 p.From.Offset = int64(int8(sc.Val()))
4382 p.To.Scale = 1
4383 case ssa.OpAMD64MOVWstoreconstidx2:
4384 p.From.Offset = int64(int16(sc.Val()))
4385 p.To.Scale = 2
4386 case ssa.OpAMD64MOVLstoreconstidx4:
4387 p.From.Offset = int64(int32(sc.Val()))
4388 p.To.Scale = 4
4389 case ssa.OpAMD64MOVQstoreconstidx8:
4390 p.From.Offset = sc.Val()
4391 p.To.Scale = 8
4392 }
4393 p.To.Type = obj.TYPE_MEM
4394 p.To.Reg = regnum(v.Args[0])
4395 p.To.Index = regnum(v.Args[1])
4396 addAux2(&p.To, v, sc.Off())
David Chase42825882015-08-20 15:14:20 -04004397 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
4398 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
Todd Neal634b50c2015-09-01 19:05:44 -05004399 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
David Chase42825882015-08-20 15:14:20 -04004400 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
4401 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
Keith Randall04d6edc2015-09-18 18:23:34 -07004402 case ssa.OpAMD64DUFFZERO:
4403 p := Prog(obj.ADUFFZERO)
4404 p.To.Type = obj.TYPE_ADDR
4405 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
4406 p.To.Offset = v.AuxInt
Keith Randall7c4fbb62015-10-19 13:56:55 -07004407 case ssa.OpAMD64MOVOconst:
4408 if v.AuxInt != 0 {
4409 v.Unimplementedf("MOVOconst can only do constant=0")
4410 }
4411 r := regnum(v)
4412 opregreg(x86.AXORPS, r, r)
Keith Randall10462eb2015-10-21 17:18:07 -07004413 case ssa.OpAMD64DUFFCOPY:
4414 p := Prog(obj.ADUFFCOPY)
4415 p.To.Type = obj.TYPE_ADDR
4416 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
4417 p.To.Offset = v.AuxInt
Keith Randall04d6edc2015-09-18 18:23:34 -07004418
Keith Randallb5c5efd2016-01-14 16:02:23 -08004419 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: use MOVQreg for reg->reg copies instead of OpCopy?
Keith Randallf7f604e2015-05-27 14:52:22 -07004420 if v.Type.IsMemory() {
4421 return
4422 }
Keith Randall083a6462015-05-12 11:06:44 -07004423 x := regnum(v.Args[0])
4424 y := regnum(v)
4425 if x != y {
Keith Randall90065ea2016-01-15 08:45:47 -08004426 opregreg(moveByType(v.Type), y, x)
Keith Randall083a6462015-05-12 11:06:44 -07004427 }
Josh Bleecher Snyder0bb2a502015-07-24 14:51:51 -07004428 case ssa.OpLoadReg:
Josh Bleecher Snyder26f135d2015-07-20 15:22:34 -07004429 if v.Type.IsFlags() {
4430 v.Unimplementedf("load flags not implemented: %v", v.LongString())
4431 return
4432 }
Keith Randall90065ea2016-01-15 08:45:47 -08004433 p := Prog(loadByType(v.Type))
Keith Randall02f4d0a2015-11-02 08:10:26 -08004434 n, off := autoVar(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07004435 p.From.Type = obj.TYPE_MEM
Keith Randalld2107fc2015-08-24 02:16:19 -07004436 p.From.Node = n
4437 p.From.Sym = Linksym(n.Sym)
Keith Randall02f4d0a2015-11-02 08:10:26 -08004438 p.From.Offset = off
Keith Randall6a8a9da2016-02-27 17:49:31 -08004439 if n.Class == PPARAM || n.Class == PPARAMOUT {
Keith Randall02f4d0a2015-11-02 08:10:26 -08004440 p.From.Name = obj.NAME_PARAM
4441 p.From.Offset += n.Xoffset
4442 } else {
4443 p.From.Name = obj.NAME_AUTO
4444 }
Keith Randall083a6462015-05-12 11:06:44 -07004445 p.To.Type = obj.TYPE_REG
4446 p.To.Reg = regnum(v)
David Chase997a9f32015-08-12 16:38:11 -04004447
Josh Bleecher Snyder0bb2a502015-07-24 14:51:51 -07004448 case ssa.OpStoreReg:
Josh Bleecher Snyder26f135d2015-07-20 15:22:34 -07004449 if v.Type.IsFlags() {
4450 v.Unimplementedf("store flags not implemented: %v", v.LongString())
4451 return
4452 }
Keith Randall90065ea2016-01-15 08:45:47 -08004453 p := Prog(storeByType(v.Type))
Keith Randall083a6462015-05-12 11:06:44 -07004454 p.From.Type = obj.TYPE_REG
4455 p.From.Reg = regnum(v.Args[0])
Keith Randall02f4d0a2015-11-02 08:10:26 -08004456 n, off := autoVar(v)
Keith Randall083a6462015-05-12 11:06:44 -07004457 p.To.Type = obj.TYPE_MEM
Keith Randalld2107fc2015-08-24 02:16:19 -07004458 p.To.Node = n
4459 p.To.Sym = Linksym(n.Sym)
Keith Randall02f4d0a2015-11-02 08:10:26 -08004460 p.To.Offset = off
Keith Randall6a8a9da2016-02-27 17:49:31 -08004461 if n.Class == PPARAM || n.Class == PPARAMOUT {
Keith Randall02f4d0a2015-11-02 08:10:26 -08004462 p.To.Name = obj.NAME_PARAM
4463 p.To.Offset += n.Xoffset
4464 } else {
4465 p.To.Name = obj.NAME_AUTO
4466 }
Keith Randall083a6462015-05-12 11:06:44 -07004467 case ssa.OpPhi:
Keith Randall0b46b422015-08-11 12:51:33 -07004468 // just check to make sure regalloc and stackalloc did it right
4469 if v.Type.IsMemory() {
4470 return
4471 }
Keith Randall083a6462015-05-12 11:06:44 -07004472 f := v.Block.Func
4473 loc := f.RegAlloc[v.ID]
4474 for _, a := range v.Args {
Josh Bleecher Snyder55845232015-08-05 16:43:49 -07004475 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
4476 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)
Keith Randall083a6462015-05-12 11:06:44 -07004477 }
4478 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08004479 case ssa.OpInitMem:
Keith Randall083a6462015-05-12 11:06:44 -07004480 // memory arg needs no code
Keith Randall02f4d0a2015-11-02 08:10:26 -08004481 case ssa.OpArg:
4482 // input args need no code
David Chase956f3192015-09-11 16:40:05 -04004483 case ssa.OpAMD64LoweredGetClosurePtr:
4484 // Output is hardwired to DX only,
4485 // and DX contains the closure pointer on
4486 // closure entry, and this "instruction"
4487 // is scheduled to the very beginning
4488 // of the entry block.
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07004489 case ssa.OpAMD64LoweredGetG:
4490 r := regnum(v)
4491 // See the comments in cmd/internal/obj/x86/obj6.go
4492 // near CanUse1InsnTLS for a detailed explanation of these instructions.
4493 if x86.CanUse1InsnTLS(Ctxt) {
4494 // MOVQ (TLS), r
4495 p := Prog(x86.AMOVQ)
4496 p.From.Type = obj.TYPE_MEM
4497 p.From.Reg = x86.REG_TLS
4498 p.To.Type = obj.TYPE_REG
4499 p.To.Reg = r
4500 } else {
4501 // MOVQ TLS, r
4502 // MOVQ (r)(TLS*1), r
4503 p := Prog(x86.AMOVQ)
4504 p.From.Type = obj.TYPE_REG
4505 p.From.Reg = x86.REG_TLS
4506 p.To.Type = obj.TYPE_REG
4507 p.To.Reg = r
4508 q := Prog(x86.AMOVQ)
4509 q.From.Type = obj.TYPE_MEM
4510 q.From.Reg = r
4511 q.From.Index = x86.REG_TLS
4512 q.From.Scale = 1
4513 q.To.Type = obj.TYPE_REG
4514 q.To.Reg = r
4515 }
Keith Randall290d8fc2015-06-10 15:03:06 -07004516 case ssa.OpAMD64CALLstatic:
Keith Randall247786c2015-05-28 10:47:24 -07004517 p := Prog(obj.ACALL)
4518 p.To.Type = obj.TYPE_MEM
4519 p.To.Name = obj.NAME_EXTERN
4520 p.To.Sym = Linksym(v.Aux.(*Sym))
Keith Randalld2107fc2015-08-24 02:16:19 -07004521 if Maxarg < v.AuxInt {
4522 Maxarg = v.AuxInt
4523 }
Keith Randall290d8fc2015-06-10 15:03:06 -07004524 case ssa.OpAMD64CALLclosure:
4525 p := Prog(obj.ACALL)
4526 p.To.Type = obj.TYPE_REG
4527 p.To.Reg = regnum(v.Args[0])
Keith Randalld2107fc2015-08-24 02:16:19 -07004528 if Maxarg < v.AuxInt {
4529 Maxarg = v.AuxInt
4530 }
Keith Randall9569b952015-08-28 22:51:01 -07004531 case ssa.OpAMD64CALLdefer:
4532 p := Prog(obj.ACALL)
4533 p.To.Type = obj.TYPE_MEM
4534 p.To.Name = obj.NAME_EXTERN
4535 p.To.Sym = Linksym(Deferproc.Sym)
4536 if Maxarg < v.AuxInt {
4537 Maxarg = v.AuxInt
4538 }
4539 // defer returns in rax:
4540 // 0 if we should continue executing
4541 // 1 if we should jump to deferreturn call
4542 p = Prog(x86.ATESTL)
4543 p.From.Type = obj.TYPE_REG
4544 p.From.Reg = x86.REG_AX
4545 p.To.Type = obj.TYPE_REG
4546 p.To.Reg = x86.REG_AX
4547 p = Prog(x86.AJNE)
4548 p.To.Type = obj.TYPE_BRANCH
4549 s.deferBranches = append(s.deferBranches, p)
4550 case ssa.OpAMD64CALLgo:
4551 p := Prog(obj.ACALL)
4552 p.To.Type = obj.TYPE_MEM
4553 p.To.Name = obj.NAME_EXTERN
4554 p.To.Sym = Linksym(Newproc.Sym)
4555 if Maxarg < v.AuxInt {
4556 Maxarg = v.AuxInt
4557 }
Keith Randalld24768e2015-09-09 23:56:59 -07004558 case ssa.OpAMD64CALLinter:
4559 p := Prog(obj.ACALL)
4560 p.To.Type = obj.TYPE_REG
4561 p.To.Reg = regnum(v.Args[0])
4562 if Maxarg < v.AuxInt {
4563 Maxarg = v.AuxInt
4564 }
Keith Randall4b803152015-07-29 17:07:09 -07004565 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4566 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
Josh Bleecher Snyder93c354b62015-07-30 17:15:16 -07004567 x := regnum(v.Args[0])
4568 r := regnum(v)
4569 if x != r {
Keith Randall90065ea2016-01-15 08:45:47 -08004570 p := Prog(moveByType(v.Type))
Josh Bleecher Snyder93c354b62015-07-30 17:15:16 -07004571 p.From.Type = obj.TYPE_REG
4572 p.From.Reg = x
4573 p.To.Type = obj.TYPE_REG
4574 p.To.Reg = r
4575 }
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02004576 p := Prog(v.Op.Asm())
4577 p.To.Type = obj.TYPE_REG
Josh Bleecher Snyder93c354b62015-07-30 17:15:16 -07004578 p.To.Reg = r
Keith Randalla329e212015-09-12 13:26:57 -07004579 case ssa.OpAMD64SQRTSD:
4580 p := Prog(v.Op.Asm())
4581 p.From.Type = obj.TYPE_REG
4582 p.From.Reg = regnum(v.Args[0])
4583 p.To.Type = obj.TYPE_REG
4584 p.To.Reg = regnum(v)
Keith Randall8c46aa52015-06-19 21:02:28 -07004585 case ssa.OpSP, ssa.OpSB:
Keith Randallcfc2aa52015-05-18 16:44:20 -07004586 // nothing to do
Josh Bleecher Snydera7940742015-07-20 15:21:49 -07004587 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4588 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4589 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
David Chase8e601b22015-08-18 14:39:26 -04004590 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004591 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
David Chase8e601b22015-08-18 14:39:26 -04004592 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004593 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
Josh Bleecher Snydera7940742015-07-20 15:21:49 -07004594 p := Prog(v.Op.Asm())
4595 p.To.Type = obj.TYPE_REG
4596 p.To.Reg = regnum(v)
David Chase8e601b22015-08-18 14:39:26 -04004597
4598 case ssa.OpAMD64SETNEF:
4599 p := Prog(v.Op.Asm())
4600 p.To.Type = obj.TYPE_REG
4601 p.To.Reg = regnum(v)
4602 q := Prog(x86.ASETPS)
4603 q.To.Type = obj.TYPE_REG
4604 q.To.Reg = x86.REG_AX
Ilya Tocare96b2322016-02-15 17:01:26 +03004605 // ORL avoids partial register write and is smaller than ORQ, used by old compiler
4606 opregreg(x86.AORL, regnum(v), x86.REG_AX)
David Chase8e601b22015-08-18 14:39:26 -04004607
4608 case ssa.OpAMD64SETEQF:
4609 p := Prog(v.Op.Asm())
4610 p.To.Type = obj.TYPE_REG
4611 p.To.Reg = regnum(v)
4612 q := Prog(x86.ASETPC)
4613 q.To.Type = obj.TYPE_REG
4614 q.To.Reg = x86.REG_AX
Ilya Tocare96b2322016-02-15 17:01:26 +03004615 // ANDL avoids partial register write and is smaller than ANDQ, used by old compiler
4616 opregreg(x86.AANDL, regnum(v), x86.REG_AX)
David Chase8e601b22015-08-18 14:39:26 -04004617
Keith Randall20550cb2015-07-28 16:04:50 -07004618 case ssa.OpAMD64InvertFlags:
4619 v.Fatalf("InvertFlags should never make it to codegen %v", v)
Keith Randall34252952016-01-05 14:56:26 -08004620 case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
4621 v.Fatalf("Flag* ops should never make it to codegen %v", v)
Keith Randall20550cb2015-07-28 16:04:50 -07004622 case ssa.OpAMD64REPSTOSQ:
4623 Prog(x86.AREP)
4624 Prog(x86.ASTOSQ)
Keith Randall10462eb2015-10-21 17:18:07 -07004625 case ssa.OpAMD64REPMOVSQ:
Keith Randall20550cb2015-07-28 16:04:50 -07004626 Prog(x86.AREP)
Keith Randall10462eb2015-10-21 17:18:07 -07004627 Prog(x86.AMOVSQ)
Keith Randalld2107fc2015-08-24 02:16:19 -07004628 case ssa.OpVarDef:
4629 Gvardef(v.Aux.(*Node))
4630 case ssa.OpVarKill:
4631 gvarkill(v.Aux.(*Node))
Keith Randall23d58102016-01-19 09:59:21 -08004632 case ssa.OpVarLive:
4633 gvarlive(v.Aux.(*Node))
Keith Randall31115a52015-10-23 19:12:49 -07004634 case ssa.OpAMD64LoweredNilCheck:
4635 // Optimization - if the subsequent block has a load or store
4636 // at the same address, we don't need to issue this instruction.
Keith Randall3c26c0d2016-01-21 13:27:01 -08004637 mem := v.Args[1]
Keith Randall31115a52015-10-23 19:12:49 -07004638 for _, w := range v.Block.Succs[0].Values {
Keith Randall3c26c0d2016-01-21 13:27:01 -08004639 if w.Op == ssa.OpPhi {
4640 if w.Type.IsMemory() {
4641 mem = w
4642 }
4643 continue
4644 }
Keith Randall31115a52015-10-23 19:12:49 -07004645 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4646 // w doesn't use a store - can't be a memory op.
4647 continue
4648 }
Keith Randall3c26c0d2016-01-21 13:27:01 -08004649 if w.Args[len(w.Args)-1] != mem {
Keith Randall31115a52015-10-23 19:12:49 -07004650 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4651 }
4652 switch w.Op {
4653 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
Keith Randall1cc57892016-01-30 11:25:38 -08004654 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore,
4655 ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVWQSXload,
Keith Randall4a346e72016-02-25 13:45:22 -08004656 ssa.OpAMD64MOVWQZXload, ssa.OpAMD64MOVLQSXload, ssa.OpAMD64MOVLQZXload,
4657 ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVOload,
4658 ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVOstore:
Keith Randall31115a52015-10-23 19:12:49 -07004659 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
Keith Randall3c26c0d2016-01-21 13:27:01 -08004660 if Debug_checknil != 0 && int(v.Line) > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08004661 Warnl(v.Line, "removed nil check")
Keith Randall3c26c0d2016-01-21 13:27:01 -08004662 }
Keith Randall31115a52015-10-23 19:12:49 -07004663 return
4664 }
Keith Randalld43f2e32015-10-21 13:13:56 -07004665 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
Keith Randallf94e0742016-01-26 15:47:08 -08004666 off := ssa.ValAndOff(v.AuxInt).Off()
Keith Randalld43f2e32015-10-21 13:13:56 -07004667 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
Keith Randall3c26c0d2016-01-21 13:27:01 -08004668 if Debug_checknil != 0 && int(v.Line) > 1 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08004669 Warnl(v.Line, "removed nil check")
Keith Randall3c26c0d2016-01-21 13:27:01 -08004670 }
Keith Randalld43f2e32015-10-21 13:13:56 -07004671 return
4672 }
Keith Randall31115a52015-10-23 19:12:49 -07004673 }
4674 if w.Type.IsMemory() {
Keith Randall4a346e72016-02-25 13:45:22 -08004675 if w.Op == ssa.OpVarDef || w.Op == ssa.OpVarKill || w.Op == ssa.OpVarLive {
4676 // these ops are OK
4677 mem = w
4678 continue
4679 }
Keith Randall31115a52015-10-23 19:12:49 -07004680 // We can't delay the nil check past the next store.
4681 break
4682 }
4683 }
4684 // Issue a load which will fault if the input is nil.
4685 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4686 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4687 // but it doesn't have false dependency on AX.
4688 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4689 // That trades clobbering flags for clobbering a register.
4690 p := Prog(x86.ATESTB)
4691 p.From.Type = obj.TYPE_REG
4692 p.From.Reg = x86.REG_AX
4693 p.To.Type = obj.TYPE_MEM
4694 p.To.Reg = regnum(v.Args[0])
4695 addAux(&p.To, v)
4696 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
Robert Griesemerb83f3972016-03-02 11:01:25 -08004697 Warnl(v.Line, "generated nil check")
Keith Randall31115a52015-10-23 19:12:49 -07004698 }
Keith Randall083a6462015-05-12 11:06:44 -07004699 default:
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004700 v.Unimplementedf("genValue not implemented: %s", v.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07004701 }
4702}
4703
Keith Randall7b773942016-01-22 13:44:58 -08004704// markMoves marks any MOVXconst ops that need to avoid clobbering flags.
4705func (s *genState) markMoves(b *ssa.Block) {
4706 flive := b.FlagsLiveAtEnd
4707 if b.Control != nil && b.Control.Type.IsFlags() {
4708 flive = true
4709 }
4710 for i := len(b.Values) - 1; i >= 0; i-- {
4711 v := b.Values[i]
Keith Randallf1f366c2016-02-29 11:10:08 -08004712 if flive && (v.Op == ssa.OpAMD64MOVBconst || v.Op == ssa.OpAMD64MOVWconst || v.Op == ssa.OpAMD64MOVLconst || v.Op == ssa.OpAMD64MOVQconst) {
Keith Randall7b773942016-01-22 13:44:58 -08004713 // The "mark" is any non-nil Aux value.
4714 v.Aux = v
4715 }
4716 if v.Type.IsFlags() {
4717 flive = false
4718 }
4719 for _, a := range v.Args {
4720 if a.Type.IsFlags() {
4721 flive = true
4722 }
4723 }
4724 }
4725}
4726
Daniel Morsing66b47812015-06-27 15:45:20 +01004727// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4728func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4729 p := Prog(as)
4730 // TODO: use zero register on archs that support it.
4731 p.From.Type = obj.TYPE_CONST
4732 p.From.Offset = 0
4733 p.To.Type = obj.TYPE_MEM
4734 p.To.Reg = regnum
4735 p.To.Offset = offset
4736 offset += width
4737 nleft = nbytes - width
4738 return nleft, offset
4739}
4740
David Chase8e601b22015-08-18 14:39:26 -04004741var blockJump = [...]struct {
4742 asm, invasm int
4743}{
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004744 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4745 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4746 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4747 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4748 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4749 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4750 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4751 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4752 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4753 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
David Chase8e601b22015-08-18 14:39:26 -04004754 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4755 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4756}
4757
4758type floatingEQNEJump struct {
4759 jump, index int
4760}
4761
4762var eqfJumps = [2][2]floatingEQNEJump{
4763 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4764 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4765}
4766var nefJumps = [2][2]floatingEQNEJump{
4767 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4768 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4769}
4770
4771func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4772 p := Prog(jumps.jump)
4773 p.To.Type = obj.TYPE_BRANCH
4774 to := jumps.index
4775 branches = append(branches, branch{p, b.Succs[to]})
4776 if to == 1 {
4777 likely = -likely
4778 }
4779 // liblink reorders the instruction stream as it sees fit.
4780 // Pass along what we know so liblink can make use of it.
4781 // TODO: Once we've fully switched to SSA,
4782 // make liblink leave our output alone.
4783 switch likely {
4784 case ssa.BranchUnlikely:
4785 p.From.Type = obj.TYPE_CONST
4786 p.From.Offset = 0
4787 case ssa.BranchLikely:
4788 p.From.Type = obj.TYPE_CONST
4789 p.From.Offset = 1
4790 }
4791 return branches
4792}
4793
Keith Randall9569b952015-08-28 22:51:01 -07004794func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
David Chase8e601b22015-08-18 14:39:26 -04004795 likely := b.Likely
4796 switch next {
4797 case b.Succs[0]:
Keith Randall9569b952015-08-28 22:51:01 -07004798 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4799 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004800 case b.Succs[1]:
Keith Randall9569b952015-08-28 22:51:01 -07004801 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4802 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004803 default:
Keith Randall9569b952015-08-28 22:51:01 -07004804 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4805 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004806 q := Prog(obj.AJMP)
4807 q.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004808 s.branches = append(s.branches, branch{q, b.Succs[1]})
David Chase8e601b22015-08-18 14:39:26 -04004809 }
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004810}
4811
Keith Randall9569b952015-08-28 22:51:01 -07004812func (s *genState) genBlock(b, next *ssa.Block) {
Michael Matloob81ccf502015-05-30 01:03:06 -04004813 lineno = b.Line
Keith Randall8d236812015-08-18 15:25:40 -07004814
Keith Randall083a6462015-05-12 11:06:44 -07004815 switch b.Kind {
Keith Randall31115a52015-10-23 19:12:49 -07004816 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
Keith Randall083a6462015-05-12 11:06:44 -07004817 if b.Succs[0] != next {
4818 p := Prog(obj.AJMP)
4819 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004820 s.branches = append(s.branches, branch{p, b.Succs[0]})
Keith Randall083a6462015-05-12 11:06:44 -07004821 }
4822 case ssa.BlockExit:
Keith Randall5f105732015-09-17 15:19:23 -07004823 Prog(obj.AUNDEF) // tell plive.go that we never reach here
Keith Randall10f38f52015-09-03 09:09:59 -07004824 case ssa.BlockRet:
Keith Randall0ec72b62015-09-08 15:42:53 -07004825 if hasdefer {
Keith Randallca9e4502015-09-08 08:59:57 -07004826 s.deferReturn()
Keith Randall9569b952015-08-28 22:51:01 -07004827 }
Keith Randall083a6462015-05-12 11:06:44 -07004828 Prog(obj.ARET)
Keith Randall8a1f6212015-09-08 21:28:44 -07004829 case ssa.BlockRetJmp:
4830 p := Prog(obj.AJMP)
4831 p.To.Type = obj.TYPE_MEM
4832 p.To.Name = obj.NAME_EXTERN
4833 p.To.Sym = Linksym(b.Aux.(*Sym))
David Chase8e601b22015-08-18 14:39:26 -04004834
4835 case ssa.BlockAMD64EQF:
Keith Randall9569b952015-08-28 22:51:01 -07004836 genFPJump(s, b, next, &eqfJumps)
David Chase8e601b22015-08-18 14:39:26 -04004837
4838 case ssa.BlockAMD64NEF:
Keith Randall9569b952015-08-28 22:51:01 -07004839 genFPJump(s, b, next, &nefJumps)
David Chase8e601b22015-08-18 14:39:26 -04004840
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004841 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4842 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4843 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4844 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4845 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004846 jmp := blockJump[b.Kind]
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004847 likely := b.Likely
4848 var p *obj.Prog
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004849 switch next {
4850 case b.Succs[0]:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004851 p = Prog(jmp.invasm)
4852 likely *= -1
Keith Randallcfc2aa52015-05-18 16:44:20 -07004853 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004854 s.branches = append(s.branches, branch{p, b.Succs[1]})
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004855 case b.Succs[1]:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004856 p = Prog(jmp.asm)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004857 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004858 s.branches = append(s.branches, branch{p, b.Succs[0]})
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004859 default:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004860 p = Prog(jmp.asm)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004861 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004862 s.branches = append(s.branches, branch{p, b.Succs[0]})
Keith Randallcfc2aa52015-05-18 16:44:20 -07004863 q := Prog(obj.AJMP)
4864 q.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004865 s.branches = append(s.branches, branch{q, b.Succs[1]})
Keith Randallcfc2aa52015-05-18 16:44:20 -07004866 }
4867
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004868 // liblink reorders the instruction stream as it sees fit.
4869 // Pass along what we know so liblink can make use of it.
4870 // TODO: Once we've fully switched to SSA,
4871 // make liblink leave our output alone.
4872 switch likely {
4873 case ssa.BranchUnlikely:
4874 p.From.Type = obj.TYPE_CONST
4875 p.From.Offset = 0
4876 case ssa.BranchLikely:
4877 p.From.Type = obj.TYPE_CONST
4878 p.From.Offset = 1
4879 }
4880
Keith Randall083a6462015-05-12 11:06:44 -07004881 default:
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004882 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07004883 }
Keith Randall083a6462015-05-12 11:06:44 -07004884}
4885
Keith Randallca9e4502015-09-08 08:59:57 -07004886func (s *genState) deferReturn() {
4887 // Deferred calls will appear to be returning to
4888 // the CALL deferreturn(SB) that we are about to emit.
4889 // However, the stack trace code will show the line
4890 // of the instruction byte before the return PC.
4891 // To avoid that being an unrelated instruction,
4892 // insert an actual hardware NOP that will have the right line number.
4893 // This is different from obj.ANOP, which is a virtual no-op
4894 // that doesn't make it into the instruction stream.
4895 s.deferTarget = Pc
4896 Thearch.Ginsnop()
4897 p := Prog(obj.ACALL)
4898 p.To.Type = obj.TYPE_MEM
4899 p.To.Name = obj.NAME_EXTERN
4900 p.To.Sym = Linksym(Deferreturn.Sym)
4901}
4902
Keith Randall8c46aa52015-06-19 21:02:28 -07004903// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4904func addAux(a *obj.Addr, v *ssa.Value) {
Keith Randalld43f2e32015-10-21 13:13:56 -07004905 addAux2(a, v, v.AuxInt)
4906}
4907func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
Keith Randall8c46aa52015-06-19 21:02:28 -07004908 if a.Type != obj.TYPE_MEM {
4909 v.Fatalf("bad addAux addr %s", a)
4910 }
4911 // add integer offset
Keith Randalld43f2e32015-10-21 13:13:56 -07004912 a.Offset += offset
Keith Randall8c46aa52015-06-19 21:02:28 -07004913
4914 // If no additional symbol offset, we're done.
4915 if v.Aux == nil {
4916 return
4917 }
4918 // Add symbol's offset from its base register.
4919 switch sym := v.Aux.(type) {
4920 case *ssa.ExternSymbol:
4921 a.Name = obj.NAME_EXTERN
4922 a.Sym = Linksym(sym.Sym.(*Sym))
4923 case *ssa.ArgSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004924 n := sym.Node.(*Node)
4925 a.Name = obj.NAME_PARAM
4926 a.Node = n
4927 a.Sym = Linksym(n.Orig.Sym)
4928 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
Keith Randall8c46aa52015-06-19 21:02:28 -07004929 case *ssa.AutoSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004930 n := sym.Node.(*Node)
4931 a.Name = obj.NAME_AUTO
4932 a.Node = n
4933 a.Sym = Linksym(n.Sym)
Keith Randall8c46aa52015-06-19 21:02:28 -07004934 default:
4935 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4936 }
4937}
4938
Keith Randall582baae2015-11-02 21:28:13 -08004939// extendIndex extends v to a full int width.
Keith Randall2a5e6c42015-07-23 14:35:02 -07004940func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4941 size := v.Type.Size()
Keith Randall582baae2015-11-02 21:28:13 -08004942 if size == s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004943 return v
4944 }
Keith Randall582baae2015-11-02 21:28:13 -08004945 if size > s.config.IntSize {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004946 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
Keith Randall2a5e6c42015-07-23 14:35:02 -07004947 // the high word and branch to out-of-bounds failure if it is not 0.
4948 s.Unimplementedf("64->32 index truncation not implemented")
4949 return v
4950 }
4951
4952 // Extend value to the required size
4953 var op ssa.Op
4954 if v.Type.IsSigned() {
Keith Randall582baae2015-11-02 21:28:13 -08004955 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004956 case 14:
4957 op = ssa.OpSignExt8to32
4958 case 18:
4959 op = ssa.OpSignExt8to64
4960 case 24:
4961 op = ssa.OpSignExt16to32
4962 case 28:
4963 op = ssa.OpSignExt16to64
4964 case 48:
4965 op = ssa.OpSignExt32to64
4966 default:
4967 s.Fatalf("bad signed index extension %s", v.Type)
4968 }
4969 } else {
Keith Randall582baae2015-11-02 21:28:13 -08004970 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004971 case 14:
4972 op = ssa.OpZeroExt8to32
4973 case 18:
4974 op = ssa.OpZeroExt8to64
4975 case 24:
4976 op = ssa.OpZeroExt16to32
4977 case 28:
4978 op = ssa.OpZeroExt16to64
4979 case 48:
4980 op = ssa.OpZeroExt32to64
4981 default:
4982 s.Fatalf("bad unsigned index extension %s", v.Type)
4983 }
4984 }
Keith Randall582baae2015-11-02 21:28:13 -08004985 return s.newValue1(op, Types[TINT], v)
Keith Randall2a5e6c42015-07-23 14:35:02 -07004986}
4987
Keith Randall083a6462015-05-12 11:06:44 -07004988// ssaRegToReg maps ssa register numbers to obj register numbers.
4989var ssaRegToReg = [...]int16{
4990 x86.REG_AX,
4991 x86.REG_CX,
4992 x86.REG_DX,
4993 x86.REG_BX,
4994 x86.REG_SP,
4995 x86.REG_BP,
4996 x86.REG_SI,
4997 x86.REG_DI,
4998 x86.REG_R8,
4999 x86.REG_R9,
5000 x86.REG_R10,
5001 x86.REG_R11,
5002 x86.REG_R12,
5003 x86.REG_R13,
5004 x86.REG_R14,
5005 x86.REG_R15,
Keith Randall8c46aa52015-06-19 21:02:28 -07005006 x86.REG_X0,
5007 x86.REG_X1,
5008 x86.REG_X2,
5009 x86.REG_X3,
5010 x86.REG_X4,
5011 x86.REG_X5,
5012 x86.REG_X6,
5013 x86.REG_X7,
5014 x86.REG_X8,
5015 x86.REG_X9,
5016 x86.REG_X10,
5017 x86.REG_X11,
5018 x86.REG_X12,
5019 x86.REG_X13,
5020 x86.REG_X14,
5021 x86.REG_X15,
5022 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
Keith Randall083a6462015-05-12 11:06:44 -07005023 // TODO: arch-dependent
5024}
5025
Keith Randall90065ea2016-01-15 08:45:47 -08005026// loadByType returns the load instruction of the given type.
5027func loadByType(t ssa.Type) int {
Ilya Tocare96b2322016-02-15 17:01:26 +03005028 // Avoid partial register write
5029 if !t.IsFloat() && t.Size() <= 2 {
5030 if t.Size() == 1 {
5031 return x86.AMOVBLZX
5032 } else {
5033 return x86.AMOVWLZX
5034 }
5035 }
5036 // Otherwise, there's no difference between load and store opcodes.
Keith Randall90065ea2016-01-15 08:45:47 -08005037 return storeByType(t)
Keith Randall9cb332e2015-07-28 14:19:20 -07005038}
5039
Keith Randall90065ea2016-01-15 08:45:47 -08005040// storeByType returns the store instruction of the given type.
5041func storeByType(t ssa.Type) int {
David Chase997a9f32015-08-12 16:38:11 -04005042 width := t.Size()
5043 if t.IsFloat() {
5044 switch width {
5045 case 4:
5046 return x86.AMOVSS
5047 case 8:
5048 return x86.AMOVSD
David Chase997a9f32015-08-12 16:38:11 -04005049 }
5050 } else {
5051 switch width {
5052 case 1:
5053 return x86.AMOVB
5054 case 2:
5055 return x86.AMOVW
5056 case 4:
5057 return x86.AMOVL
5058 case 8:
5059 return x86.AMOVQ
Keith Randall90065ea2016-01-15 08:45:47 -08005060 }
5061 }
5062 panic("bad store type")
5063}
5064
5065// moveByType returns the reg->reg move instruction of the given type.
5066func moveByType(t ssa.Type) int {
5067 if t.IsFloat() {
5068 // Moving the whole sse2 register is faster
5069 // than moving just the correct low portion of it.
Ilya Tocar1b1d0a92016-02-26 16:48:16 +03005070 // There is no xmm->xmm move with 1 byte opcode,
5071 // so use movups, which has 2 byte opcode.
5072 return x86.AMOVUPS
Keith Randall90065ea2016-01-15 08:45:47 -08005073 } else {
5074 switch t.Size() {
5075 case 1:
Ilya Tocare96b2322016-02-15 17:01:26 +03005076 // Avoids partial register write
5077 return x86.AMOVL
Keith Randall90065ea2016-01-15 08:45:47 -08005078 case 2:
Ilya Tocare96b2322016-02-15 17:01:26 +03005079 return x86.AMOVL
Keith Randall90065ea2016-01-15 08:45:47 -08005080 case 4:
5081 return x86.AMOVL
5082 case 8:
5083 return x86.AMOVQ
Keith Randallc03ed492016-03-02 15:18:40 -08005084 case 16:
5085 return x86.AMOVUPS // int128s are in SSE registers
David Chase997a9f32015-08-12 16:38:11 -04005086 default:
Keith Randallc03ed492016-03-02 15:18:40 -08005087 panic(fmt.Sprintf("bad int register width %d:%s", t.Size(), t))
David Chase997a9f32015-08-12 16:38:11 -04005088 }
5089 }
David Chase997a9f32015-08-12 16:38:11 -04005090 panic("bad register type")
5091}
5092
Keith Randall083a6462015-05-12 11:06:44 -07005093// regnum returns the register (in cmd/internal/obj numbering) to
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00005094// which v has been allocated. Panics if v is not assigned to a
Keith Randall083a6462015-05-12 11:06:44 -07005095// register.
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07005096// TODO: Make this panic again once it stops happening routinely.
Keith Randall083a6462015-05-12 11:06:44 -07005097func regnum(v *ssa.Value) int16 {
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07005098 reg := v.Block.Func.RegAlloc[v.ID]
5099 if reg == nil {
5100 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
5101 return 0
5102 }
5103 return ssaRegToReg[reg.(*ssa.Register).Num]
Keith Randall083a6462015-05-12 11:06:44 -07005104}
5105
Keith Randall02f4d0a2015-11-02 08:10:26 -08005106// autoVar returns a *Node and int64 representing the auto variable and offset within it
5107// where v should be spilled.
5108func autoVar(v *ssa.Value) (*Node, int64) {
5109 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
Keith Randall9094e3a2016-01-04 13:34:54 -08005110 if v.Type.Size() > loc.Type.Size() {
5111 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
5112 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08005113 return loc.N.(*Node), loc.Off
Keith Randall083a6462015-05-12 11:06:44 -07005114}
Keith Randallf7f604e2015-05-27 14:52:22 -07005115
Keith Randalla734bbc2016-01-11 21:05:33 -08005116// fieldIdx finds the index of the field referred to by the ODOT node n.
5117func fieldIdx(n *Node) int64 {
5118 t := n.Left.Type
5119 f := n.Right
5120 if t.Etype != TSTRUCT {
5121 panic("ODOT's LHS is not a struct")
5122 }
5123
5124 var i int64
5125 for t1 := t.Type; t1 != nil; t1 = t1.Down {
5126 if t1.Etype != TFIELD {
5127 panic("non-TFIELD in TSTRUCT")
5128 }
5129 if t1.Sym != f.Sym {
5130 i++
5131 continue
5132 }
5133 if t1.Width != n.Xoffset {
5134 panic("field offset doesn't match")
5135 }
5136 return i
5137 }
5138 panic(fmt.Sprintf("can't find field in expr %s\n", n))
5139
5140 // TODO: keep the result of this fucntion somewhere in the ODOT Node
5141 // so we don't have to recompute it each time we need it.
5142}
5143
Keith Randallf7f604e2015-05-27 14:52:22 -07005144// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005145type ssaExport struct {
5146 log bool
5147 unimplemented bool
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07005148 mustImplement bool
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005149}
Keith Randallf7f604e2015-05-27 14:52:22 -07005150
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07005151func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
5152func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
5153func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
5154func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
5155func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
5156func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
5157func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
5158func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
5159func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
David Chase52578582015-08-28 14:24:10 -04005160func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
5161func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07005162func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
5163func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
5164func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
5165func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
5166
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07005167// StringData returns a symbol (a *Sym wrapped in an interface) which
5168// is the data component of a global string constant containing s.
5169func (*ssaExport) StringData(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07005170 // TODO: is idealstring correct? It might not matter...
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07005171 _, data := stringsym(s)
5172 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
Keith Randallf7f604e2015-05-27 14:52:22 -07005173}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005174
Keith Randallc24681a2015-10-22 14:22:38 -07005175func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
Keith Randalld2107fc2015-08-24 02:16:19 -07005176 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
5177 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
5178 return n
5179}
5180
Keith Randall7d612462015-10-22 13:07:38 -07005181func (e *ssaExport) CanSSA(t ssa.Type) bool {
Keith Randall37590bd2015-09-18 22:58:10 -07005182 return canSSAType(t.(*Type))
5183}
5184
Keith Randallb5c5efd2016-01-14 16:02:23 -08005185func (e *ssaExport) Line(line int32) string {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08005186 return linestr(line)
Keith Randallb5c5efd2016-01-14 16:02:23 -08005187}
5188
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005189// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07005190func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005191 // If e was marked as unimplemented, anything could happen. Ignore.
5192 if e.log && !e.unimplemented {
5193 fmt.Printf(msg, args...)
5194 }
5195}
5196
David Chase88b230e2016-01-29 14:44:15 -05005197func (e *ssaExport) Log() bool {
5198 return e.log
5199}
5200
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005201// Fatal reports a compiler error and exits.
Keith Randallda8af472016-01-13 11:14:57 -08005202func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005203 // If e was marked as unimplemented, anything could happen. Ignore.
5204 if !e.unimplemented {
Keith Randallda8af472016-01-13 11:14:57 -08005205 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07005206 Fatalf(msg, args...)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005207 }
5208}
5209
5210// Unimplemented reports that the function cannot be compiled.
5211// It will be removed once SSA work is complete.
Keith Randallda8af472016-01-13 11:14:57 -08005212func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07005213 if e.mustImplement {
Keith Randallda8af472016-01-13 11:14:57 -08005214 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07005215 Fatalf(msg, args...)
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07005216 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07005217 const alwaysLog = false // enable to calculate top unimplemented features
5218 if !e.unimplemented && (e.log || alwaysLog) {
5219 // first implementation failure, print explanation
5220 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
5221 }
5222 e.unimplemented = true
5223}
Keith Randallc24681a2015-10-22 14:22:38 -07005224
David Chase729abfa2015-10-26 17:34:06 -04005225// Warnl reports a "warning", which is usually flag-triggered
5226// logging output for the benefit of tests.
5227func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
Robert Griesemerb83f3972016-03-02 11:01:25 -08005228 Warnl(int32(line), fmt_, args...)
David Chase729abfa2015-10-26 17:34:06 -04005229}
5230
5231func (e *ssaExport) Debug_checknil() bool {
5232 return Debug_checknil != 0
5233}
5234
Keith Randallc24681a2015-10-22 14:22:38 -07005235func (n *Node) Typ() ssa.Type {
5236 return n.Type
5237}