blob: e177ceda014c79d0660a77e003dd6801d3ea33cd [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"
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -070011 "os"
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -060012 "strings"
Keith Randalld2fd43a2015-04-15 15:51:25 -070013
Keith Randall067e8df2015-05-28 13:49:20 -070014 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070015 "cmd/internal/obj"
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -070016 "cmd/internal/sys"
Keith Randalld2fd43a2015-04-15 15:51:25 -070017)
18
Keith Randallc0740fe2016-03-03 22:06:57 -080019var ssaEnabled = true
20
Keith Randall2f57d0f2016-01-28 13:46:30 -080021var ssaConfig *ssa.Config
22var ssaExp ssaExport
23
David Chase378a8632016-02-25 13:10:51 -050024func initssa() *ssa.Config {
25 ssaExp.unimplemented = false
26 ssaExp.mustImplement = true
27 if ssaConfig == nil {
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -070028 ssaConfig = ssa.NewConfig(Thearch.LinkArch.Name, &ssaExp, Ctxt, Debug['N'] == 0)
David Chase378a8632016-02-25 13:10:51 -050029 }
30 return ssaConfig
31}
32
Keith Randall5b355a72015-12-11 20:41:52 -080033func shouldssa(fn *Node) bool {
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -070034 switch Thearch.LinkArch.Name {
Keith Randall4c9a4702016-03-21 22:57:26 -070035 default:
36 // Only available for testing.
37 if os.Getenv("SSATEST") == "" {
38 return false
39 }
40 // Generally available.
41 case "amd64":
Keith Randall5b355a72015-12-11 20:41:52 -080042 }
Keith Randallc0740fe2016-03-03 22:06:57 -080043 if !ssaEnabled {
44 return false
45 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070046
David Chasee99dd522015-10-19 11:36:07 -040047 // Environment variable control of SSA CG
48 // 1. IF GOSSAFUNC == current function name THEN
49 // compile this function with SSA and log output to ssa.html
50
David Chase729abfa2015-10-26 17:34:06 -040051 // 2. IF GOSSAHASH == "" THEN
David Chasee99dd522015-10-19 11:36:07 -040052 // compile this function (and everything else) with SSA
53
David Chase729abfa2015-10-26 17:34:06 -040054 // 3. IF GOSSAHASH == "n" or "N"
David Chasee99dd522015-10-19 11:36:07 -040055 // IF GOSSAPKG == current package name THEN
56 // compile this function (and everything in this package) with SSA
57 // ELSE
58 // use the old back end for this function.
59 // This is for compatibility with existing test harness and should go away.
60
61 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
62 // compile this function with SSA
63 // ELSE
64 // compile this function with the old back end.
65
David Chase729abfa2015-10-26 17:34:06 -040066 // Plan is for 3 to be removed when the tests are revised.
67 // SSA is now default, and is disabled by setting
68 // GOSSAHASH to n or N, or selectively with strings of
69 // 0 and 1.
David Chasee99dd522015-10-19 11:36:07 -040070
Keith Randall5b355a72015-12-11 20:41:52 -080071 name := fn.Func.Nname.Sym.Name
72
73 funcname := os.Getenv("GOSSAFUNC")
74 if funcname != "" {
75 // If GOSSAFUNC is set, compile only that function.
76 return name == funcname
77 }
78
79 pkg := os.Getenv("GOSSAPKG")
80 if pkg != "" {
81 // If GOSSAPKG is set, compile only that package.
82 return localpkg.Name == pkg
83 }
84
David Chase378a8632016-02-25 13:10:51 -050085 return initssa().DebugHashMatch("GOSSAHASH", name)
Keith Randall5b355a72015-12-11 20:41:52 -080086}
87
88// buildssa builds an SSA function.
89func buildssa(fn *Node) *ssa.Func {
90 name := fn.Func.Nname.Sym.Name
Keith Randall59681802016-03-01 13:47:48 -080091 printssa := name == os.Getenv("GOSSAFUNC")
Keith Randall5b355a72015-12-11 20:41:52 -080092 if printssa {
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -070093 fmt.Println("generating SSA for", name)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080094 dumplist("buildssa-enter", fn.Func.Enter)
95 dumplist("buildssa-body", fn.Nbody)
96 dumplist("buildssa-exit", fn.Func.Exit)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070097 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070098
Keith Randallcfc2aa52015-05-18 16:44:20 -070099 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -0400100 s.pushLine(fn.Lineno)
101 defer s.popLine()
102
Keith Randall6a8a9da2016-02-27 17:49:31 -0800103 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
104 s.cgoUnsafeArgs = true
105 }
Keith Randall15ed37d2016-03-16 21:51:17 -0700106 if fn.Func.Pragma&Nowritebarrier != 0 {
107 s.noWB = true
108 }
109 defer func() {
110 if s.WBLineno != 0 {
111 fn.Func.WBLineno = s.WBLineno
112 }
113 }()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700114 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700115
Keith Randall2f57d0f2016-01-28 13:46:30 -0800116 ssaExp.log = printssa
David Chase378a8632016-02-25 13:10:51 -0500117
118 s.config = initssa()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700119 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700120 s.f.Name = name
David Chase8824dcc2015-10-08 12:39:56 -0400121 s.exitCode = fn.Func.Exit
Keith Randall74e568f2015-11-09 21:35:40 -0800122 s.panics = map[funcLine]*ssa.Block{}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700123
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700124 if name == os.Getenv("GOSSAFUNC") {
125 // TODO: tempfile? it is handy to have the location
126 // of this file be stable, so you can just reload in the browser.
Keith Randallda8af472016-01-13 11:14:57 -0800127 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700128 // TODO: generate and print a mapping from nodes to values and blocks
129 }
130 defer func() {
Keith Randall5b355a72015-12-11 20:41:52 -0800131 if !printssa {
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700132 s.config.HTML.Close()
133 }
134 }()
135
Keith Randalld2fd43a2015-04-15 15:51:25 -0700136 // Allocate starting block
137 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
138
Keith Randallcfc2aa52015-05-18 16:44:20 -0700139 // Allocate starting values
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700140 s.labels = map[string]*ssaLabel{}
141 s.labeledNodes = map[*Node]*ssaLabel{}
Keith Randall02f4d0a2015-11-02 08:10:26 -0800142 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -0700143 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
144 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
Keith Randall8c46aa52015-06-19 21:02:28 -0700145
David Chase956f3192015-09-11 16:40:05 -0400146 s.startBlock(s.f.Entry)
147 s.vars[&memVar] = s.startmem
148
Todd Neald076ef72015-10-15 20:25:32 -0500149 s.varsyms = map[*Node]interface{}{}
150
Keith Randall8c46aa52015-06-19 21:02:28 -0700151 // Generate addresses of local declarations
152 s.decladdrs = map[*Node]*ssa.Value{}
Keith Randall4fffd4562016-02-29 13:31:48 -0800153 for _, n := range fn.Func.Dcl {
Keith Randall8c46aa52015-06-19 21:02:28 -0700154 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -0800155 case PPARAM, PPARAMOUT:
Todd Neald076ef72015-10-15 20:25:32 -0500156 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randall8c46aa52015-06-19 21:02:28 -0700157 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800158 if n.Class == PPARAMOUT && s.canSSA(n) {
159 // Save ssa-able PPARAMOUT variables so we can
160 // store them back to the stack at the end of
161 // the function.
162 s.returns = append(s.returns, n)
163 }
David Chase956f3192015-09-11 16:40:05 -0400164 case PAUTO | PHEAP:
165 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
Todd Neald076ef72015-10-15 20:25:32 -0500166 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
David Chase956f3192015-09-11 16:40:05 -0400167 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase8824dcc2015-10-08 12:39:56 -0400168 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
169 // This ends up wrong, have to do it at the PARAM node instead.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800170 case PAUTO:
Keith Randalld2107fc2015-08-24 02:16:19 -0700171 // processed at each use, to prevent Addr coming
172 // before the decl.
Keith Randallc3eb1a72015-09-06 13:42:26 -0700173 case PFUNC:
174 // local function - already handled by frontend
Daniel Morsingbe2a3e22015-07-01 20:37:25 +0100175 default:
176 str := ""
177 if n.Class&PHEAP != 0 {
178 str = ",heap"
179 }
Josh Bleecher Snyder58446032015-08-23 20:29:43 -0700180 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -0700181 }
182 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700183
184 // Convert the AST-based IR to the SSA-based IR
Keith Randall4fffd4562016-02-29 13:31:48 -0800185 s.stmts(fn.Func.Enter)
Keith Randall9d854fd2016-03-01 12:50:17 -0800186 s.stmts(fn.Nbody)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700187
Keith Randallcfc2aa52015-05-18 16:44:20 -0700188 // fallthrough to exit
Keith Randalla7cfc7592015-09-08 16:04:37 -0700189 if s.curBlock != nil {
Keith Randallddc6b642016-03-09 19:27:57 -0800190 s.pushLine(fn.Func.Endlineno)
191 s.exit()
192 s.popLine()
Keith Randallcfc2aa52015-05-18 16:44:20 -0700193 }
194
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700195 // Check that we used all labels
196 for name, lab := range s.labels {
197 if !lab.used() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800198 yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700199 lab.reported = true
200 }
201 if lab.used() && !lab.defined() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800202 yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700203 lab.reported = true
204 }
205 }
206
207 // Check any forward gotos. Non-forward gotos have already been checked.
208 for _, n := range s.fwdGotos {
209 lab := s.labels[n.Left.Sym.Name]
210 // If the label is undefined, we have already have printed an error.
211 if lab.defined() {
212 s.checkgoto(n, lab.defNode)
213 }
214 }
215
216 if nerrors > 0 {
Keith Randall4c5459d2016-01-28 16:11:56 -0800217 s.f.Free()
Keith Randall5b355a72015-12-11 20:41:52 -0800218 return nil
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700219 }
220
Keith Randalld2fd43a2015-04-15 15:51:25 -0700221 // Link up variable uses to variable definitions
222 s.linkForwardReferences()
223
David Chase8824dcc2015-10-08 12:39:56 -0400224 // Don't carry reference this around longer than necessary
Keith Randall4fffd4562016-02-29 13:31:48 -0800225 s.exitCode = Nodes{}
David Chase8824dcc2015-10-08 12:39:56 -0400226
Josh Bleecher Snyder983bc8d2015-07-17 16:47:43 +0000227 // Main call to ssa package to compile function
228 ssa.Compile(s.f)
229
Keith Randall5b355a72015-12-11 20:41:52 -0800230 return s.f
Keith Randalld2fd43a2015-04-15 15:51:25 -0700231}
232
Keith Randallcfc2aa52015-05-18 16:44:20 -0700233type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700234 // configuration (arch) information
235 config *ssa.Config
236
237 // function we're building
238 f *ssa.Func
239
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700240 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
241 labels map[string]*ssaLabel
242 labeledNodes map[*Node]*ssaLabel
243
244 // gotos that jump forward; required for deferred checkgoto calls
245 fwdGotos []*Node
David Chase8824dcc2015-10-08 12:39:56 -0400246 // Code that must precede any return
247 // (e.g., copying value of heap-escaped paramout back to true paramout)
Keith Randall4fffd4562016-02-29 13:31:48 -0800248 exitCode Nodes
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700249
250 // unlabeled break and continue statement tracking
251 breakTo *ssa.Block // current target for plain break statement
252 continueTo *ssa.Block // current target for plain continue statement
Keith Randalld2fd43a2015-04-15 15:51:25 -0700253
254 // current location where we're interpreting the AST
255 curBlock *ssa.Block
256
Keith Randall8c46aa52015-06-19 21:02:28 -0700257 // variable assignments in the current block (map from variable symbol to ssa value)
258 // *Node is the unique identifier (an ONAME Node) for the variable.
259 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700260
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000261 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700262 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700263
Keith Randalld2107fc2015-08-24 02:16:19 -0700264 // addresses of PPARAM and PPARAMOUT variables.
Keith Randall8c46aa52015-06-19 21:02:28 -0700265 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700266
Todd Neald076ef72015-10-15 20:25:32 -0500267 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
268 varsyms map[*Node]interface{}
269
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000270 // starting values. Memory, stack pointer, and globals pointer
Keith Randallcfc2aa52015-05-18 16:44:20 -0700271 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700272 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700273 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400274
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000275 // line number stack. The current line number is top of stack
Michael Matloob81ccf502015-05-30 01:03:06 -0400276 line []int32
Keith Randall74e568f2015-11-09 21:35:40 -0800277
278 // list of panic calls by function name and line number.
279 // Used to deduplicate panic calls.
280 panics map[funcLine]*ssa.Block
Keith Randallb5c5efd2016-01-14 16:02:23 -0800281
282 // list of FwdRef values.
283 fwdRefs []*ssa.Value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800284
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000285 // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800286 returns []*Node
287
288 cgoUnsafeArgs bool
Keith Randall15ed37d2016-03-16 21:51:17 -0700289 noWB bool
290 WBLineno int32 // line number of first write barrier. 0=no write barriers
Keith Randall74e568f2015-11-09 21:35:40 -0800291}
292
293type funcLine struct {
294 f *Node
295 line int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700296}
297
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700298type ssaLabel struct {
299 target *ssa.Block // block identified by this label
300 breakTarget *ssa.Block // block to break to in control flow node identified by this label
301 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
302 defNode *Node // label definition Node (OLABEL)
303 // Label use Node (OGOTO, OBREAK, OCONTINUE).
304 // Used only for error detection and reporting.
305 // There might be multiple uses, but we only need to track one.
306 useNode *Node
307 reported bool // reported indicates whether an error has already been reported for this label
308}
309
310// defined reports whether the label has a definition (OLABEL node).
311func (l *ssaLabel) defined() bool { return l.defNode != nil }
312
313// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
314func (l *ssaLabel) used() bool { return l.useNode != nil }
315
316// label returns the label associated with sym, creating it if necessary.
317func (s *state) label(sym *Sym) *ssaLabel {
318 lab := s.labels[sym.Name]
319 if lab == nil {
320 lab = new(ssaLabel)
321 s.labels[sym.Name] = lab
322 }
323 return lab
324}
325
Keith Randallda8af472016-01-13 11:14:57 -0800326func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
David Chase88b230e2016-01-29 14:44:15 -0500327func (s *state) Log() bool { return s.config.Log() }
Keith Randallda8af472016-01-13 11:14:57 -0800328func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
329func (s *state) Unimplementedf(msg string, args ...interface{}) {
330 s.config.Unimplementedf(s.peekLine(), msg, args...)
331}
Todd Neal98b88de2016-03-13 23:04:31 -0500332func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
333func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700334
Keith Randall269baa92015-09-17 10:31:16 -0700335var (
336 // dummy node for the memory variable
Keith Randallc24681a2015-10-22 14:22:38 -0700337 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
Keith Randall8c46aa52015-06-19 21:02:28 -0700338
Keith Randall269baa92015-09-17 10:31:16 -0700339 // dummy nodes for temporary variables
Josh Bleecher Snyder6b33b0e2016-04-10 09:08:00 -0700340 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -0700341 lenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "len"}}
Josh Bleecher Snyder6b33b0e2016-04-10 09:08:00 -0700342 newlenVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "newlen"}}
343 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
344 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
345 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
346 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
347 deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
Keith Randall269baa92015-09-17 10:31:16 -0700348)
Keith Randall5505e8c2015-09-12 23:27:26 -0700349
Keith Randalld2fd43a2015-04-15 15:51:25 -0700350// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700351func (s *state) startBlock(b *ssa.Block) {
352 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700353 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700354 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700355 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700356 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700357}
358
359// endBlock marks the end of generating code for the current block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000360// Returns the (former) current block. Returns nil if there is no current
Keith Randalld2fd43a2015-04-15 15:51:25 -0700361// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700362func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700363 b := s.curBlock
364 if b == nil {
365 return nil
366 }
367 for len(s.defvars) <= int(b.ID) {
368 s.defvars = append(s.defvars, nil)
369 }
370 s.defvars[b.ID] = s.vars
371 s.curBlock = nil
372 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400373 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700374 return b
375}
376
Michael Matloob81ccf502015-05-30 01:03:06 -0400377// pushLine pushes a line number on the line number stack.
378func (s *state) pushLine(line int32) {
379 s.line = append(s.line, line)
380}
381
382// popLine pops the top of the line number stack.
383func (s *state) popLine() {
384 s.line = s.line[:len(s.line)-1]
385}
386
387// peekLine peek the top of the line number stack.
388func (s *state) peekLine() int32 {
389 return s.line[len(s.line)-1]
390}
391
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700392func (s *state) Error(msg string, args ...interface{}) {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800393 yyerrorl(s.peekLine(), msg, args...)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700394}
395
Keith Randall8f22b522015-06-11 21:29:25 -0700396// newValue0 adds a new value with no arguments to the current block.
397func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
398 return s.curBlock.NewValue0(s.peekLine(), op, t)
399}
400
401// newValue0A adds a new value with no arguments and an aux value to the current block.
402func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
403 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400404}
405
Todd Neal991036a2015-09-03 18:24:22 -0500406// newValue0I adds a new value with no arguments and an auxint value to the current block.
407func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
408 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
409}
410
Michael Matloob81ccf502015-05-30 01:03:06 -0400411// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700412func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
413 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
414}
415
416// newValue1A adds a new value with one argument and an aux value to the current block.
417func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
418 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400419}
420
Keith Randallcd7e0592015-07-15 21:33:49 -0700421// newValue1I adds a new value with one argument and an auxint value to the current block.
422func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
423 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
424}
425
Michael Matloob81ccf502015-05-30 01:03:06 -0400426// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700427func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
428 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400429}
430
Daniel Morsing66b47812015-06-27 15:45:20 +0100431// newValue2I adds a new value with two arguments and an auxint value to the current block.
432func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
433 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
434}
435
Michael Matloob81ccf502015-05-30 01:03:06 -0400436// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700437func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
438 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400439}
440
Keith Randalld4cc51d2015-08-14 21:47:20 -0700441// newValue3I adds a new value with three arguments and an auxint value to the current block.
442func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
443 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
444}
445
Todd Neal991036a2015-09-03 18:24:22 -0500446// entryNewValue0 adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700447func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
448 return s.f.Entry.NewValue0(s.peekLine(), op, t)
449}
450
Todd Neal991036a2015-09-03 18:24:22 -0500451// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700452func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
453 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400454}
455
Todd Neal991036a2015-09-03 18:24:22 -0500456// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
457func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
458 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
459}
460
Michael Matloob81ccf502015-05-30 01:03:06 -0400461// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700462func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
463 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
464}
465
466// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
467func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
468 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400469}
470
Keith Randall8c46aa52015-06-19 21:02:28 -0700471// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
472func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
473 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
474}
475
Michael Matloob81ccf502015-05-30 01:03:06 -0400476// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700477func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
478 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400479}
480
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700481// const* routines add a new const value to the entry block.
Josh Bleecher Snyder39214272016-03-06 18:06:09 -0800482func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) }
483func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) }
484func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) }
485func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700486func (s *state) constBool(c bool) *ssa.Value {
487 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
488}
Keith Randall9cb332e2015-07-28 14:19:20 -0700489func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
490 return s.f.ConstInt8(s.peekLine(), t, c)
491}
492func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
493 return s.f.ConstInt16(s.peekLine(), t, c)
494}
495func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
496 return s.f.ConstInt32(s.peekLine(), t, c)
497}
498func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
499 return s.f.ConstInt64(s.peekLine(), t, c)
500}
David Chase997a9f32015-08-12 16:38:11 -0400501func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
502 return s.f.ConstFloat32(s.peekLine(), t, c)
503}
504func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
505 return s.f.ConstFloat64(s.peekLine(), t, c)
506}
Michael Matloob81ccf502015-05-30 01:03:06 -0400507func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
Keith Randall9cb332e2015-07-28 14:19:20 -0700508 if s.config.IntSize == 8 {
509 return s.constInt64(t, c)
510 }
511 if int64(int32(c)) != c {
512 s.Fatalf("integer constant too big %d", c)
513 }
514 return s.constInt32(t, int32(c))
Michael Matloob81ccf502015-05-30 01:03:06 -0400515}
516
Keith Randall4fffd4562016-02-29 13:31:48 -0800517func (s *state) stmts(a Nodes) {
518 for _, x := range a.Slice() {
519 s.stmt(x)
520 }
521}
522
Keith Randalld2fd43a2015-04-15 15:51:25 -0700523// ssaStmtList converts the statement n to SSA and adds it to s.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800524func (s *state) stmtList(l Nodes) {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800525 for _, n := range l.Slice() {
526 s.stmt(n)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700527 }
528}
529
530// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700531func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400532 s.pushLine(n.Lineno)
533 defer s.popLine()
534
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700535 // If s.curBlock is nil, then we're about to generate dead code.
536 // We can't just short-circuit here, though,
537 // because we check labels and gotos as part of SSA generation.
538 // Provide a block for the dead code so that we don't have
539 // to add special cases everywhere else.
540 if s.curBlock == nil {
541 dead := s.f.NewBlock(ssa.BlockPlain)
542 s.startBlock(dead)
543 }
544
Keith Randalld2fd43a2015-04-15 15:51:25 -0700545 s.stmtList(n.Ninit)
546 switch n.Op {
547
548 case OBLOCK:
549 s.stmtList(n.List)
550
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600551 // No-ops
Todd Neal67e43c12015-08-28 21:19:40 -0500552 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600553
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600554 // Expression statements
555 case OCALLFUNC, OCALLMETH, OCALLINTER:
Keith Randalld24768e2015-09-09 23:56:59 -0700556 s.call(n, callNormal)
Keith Randallfb54e032016-02-24 16:19:20 -0800557 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
Matthew Dempsky980ab122016-04-13 18:37:18 -0700558 (compiling_runtime && n.Left.Sym.Name == "throw" ||
Keith Randall6a8a9da2016-02-27 17:49:31 -0800559 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 -0800560 m := s.mem()
561 b := s.endBlock()
562 b.Kind = ssa.BlockExit
Keith Randall56e0ecc2016-03-15 20:45:50 -0700563 b.SetControl(m)
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800564 // TODO: never rewrite OPANIC to OCALLFUNC in the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000565 // first place. Need to wait until all backends
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800566 // go through SSA.
567 }
Keith Randalld24768e2015-09-09 23:56:59 -0700568 case ODEFER:
569 s.call(n.Left, callDefer)
570 case OPROC:
571 s.call(n.Left, callGo)
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600572
Keith Randall269baa92015-09-17 10:31:16 -0700573 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800574 res, resok := s.dottype(n.Rlist.First(), true)
Keith Randalld4663e12016-03-21 10:22:03 -0700575 s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0)
576 s.assign(n.List.Second(), resok, false, false, n.Lineno, 0)
Keith Randall269baa92015-09-17 10:31:16 -0700577 return
578
Keith Randalld2fd43a2015-04-15 15:51:25 -0700579 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100580 if n.Left.Class&PHEAP == 0 {
581 return
582 }
Matthew Dempsky980ab122016-04-13 18:37:18 -0700583 if compiling_runtime {
Keith Randall0ec72b62015-09-08 15:42:53 -0700584 Fatalf("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100585 }
586
587 // TODO: the old pass hides the details of PHEAP
588 // variables behind ONAME nodes. Figure out if it's better
589 // to rewrite the tree and make the heapaddr construct explicit
590 // or to keep this detail hidden behind the scenes.
591 palloc := prealloc[n.Left]
592 if palloc == nil {
593 palloc = callnew(n.Left.Type)
594 prealloc[n.Left] = palloc
595 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700596 r := s.expr(palloc)
Keith Randalld4663e12016-03-21 10:22:03 -0700597 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700598
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700599 case OLABEL:
600 sym := n.Left.Sym
601
602 if isblanksym(sym) {
Keith Randall7e4c06d2015-07-12 11:52:09 -0700603 // Empty identifier is valid but useless.
604 // See issues 11589, 11593.
605 return
606 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700607
608 lab := s.label(sym)
609
610 // Associate label with its control flow node, if any
611 if ctl := n.Name.Defn; ctl != nil {
612 switch ctl.Op {
613 case OFOR, OSWITCH, OSELECT:
614 s.labeledNodes[ctl] = lab
615 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700616 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700617
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700618 if !lab.defined() {
619 lab.defNode = n
620 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800621 s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700622 lab.reported = true
Keith Randalld2fd43a2015-04-15 15:51:25 -0700623 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700624 // The label might already have a target block via a goto.
625 if lab.target == nil {
626 lab.target = s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700627 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700628
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700629 // go to that label (we pretend "label:" is preceded by "goto label")
630 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500631 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700632 s.startBlock(lab.target)
633
634 case OGOTO:
635 sym := n.Left.Sym
636
637 lab := s.label(sym)
638 if lab.target == nil {
639 lab.target = s.f.NewBlock(ssa.BlockPlain)
640 }
641 if !lab.used() {
642 lab.useNode = n
643 }
644
645 if lab.defined() {
646 s.checkgoto(n, lab.defNode)
647 } else {
648 s.fwdGotos = append(s.fwdGotos, n)
649 }
650
651 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500652 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700653
Keith Randall290d8fc2015-06-10 15:03:06 -0700654 case OAS, OASWB:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700655 // Check whether we can generate static data rather than code.
656 // If so, ignore n and defer data generation until codegen.
657 // Failure to do this causes writes to readonly symbols.
658 if gen_as_init(n, true) {
659 var data []*Node
660 if s.f.StaticData != nil {
661 data = s.f.StaticData.([]*Node)
662 }
663 s.f.StaticData = append(data, n)
664 return
665 }
Keith Randall5ba31942016-01-25 17:06:54 -0800666
Keith Randall309144b2016-04-01 11:05:30 -0700667 if n.Left == n.Right && n.Left.Op == ONAME {
668 // An x=x assignment. No point in doing anything
669 // here. In addition, skipping this assignment
670 // prevents generating:
671 // VARDEF x
672 // COPY x -> x
673 // which is bad because x is incorrectly considered
674 // dead before the vardef. See issue #14904.
675 return
676 }
677
Keith Randall5ba31942016-01-25 17:06:54 -0800678 var t *Type
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700679 if n.Right != nil {
Keith Randall5ba31942016-01-25 17:06:54 -0800680 t = n.Right.Type
681 } else {
682 t = n.Left.Type
683 }
684
685 // Evaluate RHS.
686 rhs := n.Right
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -0700687 if rhs != nil {
688 switch rhs.Op {
689 case OSTRUCTLIT, OARRAYLIT:
690 // All literals with nonzero fields have already been
691 // rewritten during walk. Any that remain are just T{}
692 // or equivalents. Use the zero value.
693 if !iszero(rhs) {
694 Fatalf("literal with nonzero value in SSA: %v", rhs)
695 }
696 rhs = nil
697 case OAPPEND:
698 // If we're writing the result of an append back to the same slice,
699 // handle it specially to avoid write barriers on the fast (non-growth) path.
700 // If the slice can be SSA'd, it'll be on the stack,
701 // so there will be no write barriers,
702 // so there's no need to attempt to prevent them.
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -0700703 if samesafeexpr(n.Left, rhs.List.First()) && !s.canSSA(n.Left) {
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -0700704 s.append(rhs, true)
705 return
706 }
Keith Randall5ba31942016-01-25 17:06:54 -0800707 }
Keith Randall5ba31942016-01-25 17:06:54 -0800708 }
709 var r *ssa.Value
710 needwb := n.Op == OASWB && rhs != nil
711 deref := !canSSAType(t)
712 if deref {
713 if rhs == nil {
714 r = nil // Signal assign to use OpZero.
Keith Randalld3886902015-09-18 22:12:38 -0700715 } else {
Keith Randall5ba31942016-01-25 17:06:54 -0800716 r = s.addr(rhs, false)
717 }
718 } else {
719 if rhs == nil {
720 r = s.zeroVal(t)
721 } else {
722 r = s.expr(rhs)
Keith Randalld3886902015-09-18 22:12:38 -0700723 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700724 }
Keith Randall5ba31942016-01-25 17:06:54 -0800725 if rhs != nil && rhs.Op == OAPPEND {
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -0700726 // The frontend gets rid of the write barrier to enable the special OAPPEND
727 // handling above, but since this is not a special case, we need it.
Keith Randall9d22c102015-09-11 11:02:57 -0700728 // TODO: just add a ptr graying to the end of growslice?
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -0700729 // TODO: check whether we need to provide special handling and a write barrier
730 // for ODOTTYPE and ORECV also.
Keith Randall9d22c102015-09-11 11:02:57 -0700731 // They get similar wb-removal treatment in walk.go:OAS.
Keith Randall5ba31942016-01-25 17:06:54 -0800732 needwb = true
Keith Randall9d22c102015-09-11 11:02:57 -0700733 }
Keith Randall5ba31942016-01-25 17:06:54 -0800734
Keith Randalld4663e12016-03-21 10:22:03 -0700735 var skip skipMask
736 if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
737 // We're assigning a slicing operation back to its source.
738 // Don't write back fields we aren't changing. See issue #14855.
739 i := rhs.Right.Left
740 var j, k *Node
741 if rhs.Op == OSLICE3 {
742 j = rhs.Right.Right.Left
743 k = rhs.Right.Right.Right
744 } else {
745 j = rhs.Right.Right
746 }
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -0700747 if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
Keith Randalld4663e12016-03-21 10:22:03 -0700748 // [0:...] is the same as [:...]
749 i = nil
750 }
751 // TODO: detect defaults for len/cap also.
752 // Currently doesn't really work because (*p)[:len(*p)] appears here as:
753 // tmp = len(*p)
754 // (*p)[:tmp]
755 //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) {
756 // j = nil
757 //}
758 //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) {
759 // k = nil
760 //}
761 if i == nil {
762 skip |= skipPtr
763 if j == nil {
764 skip |= skipLen
765 }
766 if k == nil {
767 skip |= skipCap
768 }
769 }
770 }
771
772 s.assign(n.Left, r, needwb, deref, n.Lineno, skip)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100773
Keith Randalld2fd43a2015-04-15 15:51:25 -0700774 case OIF:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700775 bThen := s.f.NewBlock(ssa.BlockPlain)
776 bEnd := s.f.NewBlock(ssa.BlockPlain)
777 var bElse *ssa.Block
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800778 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700779 bElse = s.f.NewBlock(ssa.BlockPlain)
Keith Randall99187312015-11-02 16:56:53 -0800780 s.condBranch(n.Left, bThen, bElse, n.Likely)
781 } else {
782 s.condBranch(n.Left, bThen, bEnd, n.Likely)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700783 }
784
785 s.startBlock(bThen)
Keith Randall9d854fd2016-03-01 12:50:17 -0800786 s.stmts(n.Nbody)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700787 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500788 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700789 }
790
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800791 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700792 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700793 s.stmtList(n.Rlist)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700794 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500795 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700796 }
797 }
798 s.startBlock(bEnd)
799
800 case ORETURN:
801 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800802 s.exit()
Keith Randall8a1f6212015-09-08 21:28:44 -0700803 case ORETJMP:
804 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800805 b := s.exit()
806 b.Kind = ssa.BlockRetJmp // override BlockRet
Keith Randall8a1f6212015-09-08 21:28:44 -0700807 b.Aux = n.Left.Sym
Keith Randalld2fd43a2015-04-15 15:51:25 -0700808
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700809 case OCONTINUE, OBREAK:
810 var op string
811 var to *ssa.Block
812 switch n.Op {
813 case OCONTINUE:
814 op = "continue"
815 to = s.continueTo
816 case OBREAK:
817 op = "break"
818 to = s.breakTo
819 }
820 if n.Left == nil {
821 // plain break/continue
822 if to == nil {
823 s.Error("%s is not in a loop", op)
824 return
825 }
826 // nothing to do; "to" is already the correct target
827 } else {
828 // labeled break/continue; look up the target
829 sym := n.Left.Sym
830 lab := s.label(sym)
831 if !lab.used() {
832 lab.useNode = n.Left
833 }
834 if !lab.defined() {
835 s.Error("%s label not defined: %v", op, sym)
836 lab.reported = true
837 return
838 }
839 switch n.Op {
840 case OCONTINUE:
841 to = lab.continueTarget
842 case OBREAK:
843 to = lab.breakTarget
844 }
845 if to == nil {
846 // Valid label but not usable with a break/continue here, e.g.:
847 // for {
848 // continue abc
849 // }
850 // abc:
851 // for {}
852 s.Error("invalid %s label %v", op, sym)
853 lab.reported = true
854 return
855 }
856 }
857
858 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500859 b.AddEdgeTo(to)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700860
Keith Randalld2fd43a2015-04-15 15:51:25 -0700861 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700862 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700863 bCond := s.f.NewBlock(ssa.BlockPlain)
864 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700865 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700866 bEnd := s.f.NewBlock(ssa.BlockPlain)
867
868 // first, jump to condition test
869 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500870 b.AddEdgeTo(bCond)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700871
872 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700873 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700874 if n.Left != nil {
Keith Randall99187312015-11-02 16:56:53 -0800875 s.condBranch(n.Left, bBody, bEnd, 1)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700876 } else {
Keith Randall99187312015-11-02 16:56:53 -0800877 b := s.endBlock()
878 b.Kind = ssa.BlockPlain
879 b.AddEdgeTo(bBody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700880 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700881
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700882 // set up for continue/break in body
883 prevContinue := s.continueTo
884 prevBreak := s.breakTo
885 s.continueTo = bIncr
886 s.breakTo = bEnd
887 lab := s.labeledNodes[n]
888 if lab != nil {
889 // labeled for loop
890 lab.continueTarget = bIncr
891 lab.breakTarget = bEnd
892 }
893
Keith Randalld2fd43a2015-04-15 15:51:25 -0700894 // generate body
895 s.startBlock(bBody)
Keith Randall9d854fd2016-03-01 12:50:17 -0800896 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700897
898 // tear down continue/break
899 s.continueTo = prevContinue
900 s.breakTo = prevBreak
901 if lab != nil {
902 lab.continueTarget = nil
903 lab.breakTarget = nil
904 }
905
906 // done with body, goto incr
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700907 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500908 b.AddEdgeTo(bIncr)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700909 }
910
911 // generate incr
912 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700913 if n.Right != nil {
914 s.stmt(n.Right)
915 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700916 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500917 b.AddEdgeTo(bCond)
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700918 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700919 s.startBlock(bEnd)
920
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700921 case OSWITCH, OSELECT:
922 // These have been mostly rewritten by the front end into their Nbody fields.
923 // Our main task is to correctly hook up any break statements.
924 bEnd := s.f.NewBlock(ssa.BlockPlain)
925
926 prevBreak := s.breakTo
927 s.breakTo = bEnd
928 lab := s.labeledNodes[n]
929 if lab != nil {
930 // labeled
931 lab.breakTarget = bEnd
932 }
933
934 // generate body code
Keith Randall9d854fd2016-03-01 12:50:17 -0800935 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700936
937 s.breakTo = prevBreak
938 if lab != nil {
939 lab.breakTarget = nil
940 }
941
Keith Randalleb0cff92016-02-09 12:28:02 -0800942 // OSWITCH never falls through (s.curBlock == nil here).
943 // OSELECT does not fall through if we're calling selectgo.
944 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
945 // In those latter cases, go to the code after the select.
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700946 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500947 b.AddEdgeTo(bEnd)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700948 }
949 s.startBlock(bEnd)
950
Keith Randalld2fd43a2015-04-15 15:51:25 -0700951 case OVARKILL:
Keith Randalld2107fc2015-08-24 02:16:19 -0700952 // Insert a varkill op to record that a variable is no longer live.
953 // We only care about liveness info at call sites, so putting the
954 // varkill in the store chain is enough to keep it correctly ordered
955 // with respect to call ops.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800956 if !s.canSSA(n.Left) {
Keith Randalld29e92b2015-09-19 12:01:39 -0700957 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
958 }
Keith Randall9569b952015-08-28 22:51:01 -0700959
Keith Randall23d58102016-01-19 09:59:21 -0800960 case OVARLIVE:
961 // Insert a varlive op to record that a variable is still live.
962 if !n.Left.Addrtaken {
963 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
964 }
965 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
966
Keith Randall46ffb022015-09-12 14:06:44 -0700967 case OCHECKNIL:
968 p := s.expr(n.Left)
969 s.nilCheck(p)
970
Keith Randalld2fd43a2015-04-15 15:51:25 -0700971 default:
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -0700972 s.Unimplementedf("unhandled stmt %s", n.Op)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700973 }
974}
975
Keith Randall6a8a9da2016-02-27 17:49:31 -0800976// exit processes any code that needs to be generated just before returning.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000977// It returns a BlockRet block that ends the control flow. Its control value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800978// will be set to the final memory state.
979func (s *state) exit() *ssa.Block {
Keith Randallddc6b642016-03-09 19:27:57 -0800980 if hasdefer {
981 s.rtcall(Deferreturn, true, nil)
982 }
983
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000984 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
Keith Randall6a8a9da2016-02-27 17:49:31 -0800985 // variables back to the stack.
986 s.stmts(s.exitCode)
987
988 // Store SSAable PPARAMOUT variables back to stack locations.
989 for _, n := range s.returns {
990 aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
991 addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
992 val := s.variable(n, n.Type)
993 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
994 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
995 // TODO: if val is ever spilled, we'd like to use the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000996 // PPARAMOUT slot for spilling it. That won't happen
Keith Randall6a8a9da2016-02-27 17:49:31 -0800997 // currently.
998 }
999
1000 // Do actual return.
1001 m := s.mem()
1002 b := s.endBlock()
1003 b.Kind = ssa.BlockRet
Keith Randall56e0ecc2016-03-15 20:45:50 -07001004 b.SetControl(m)
Keith Randall6a8a9da2016-02-27 17:49:31 -08001005 return b
1006}
1007
Keith Randall67fdb0d2015-07-19 15:48:20 -07001008type opAndType struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001009 op Op
1010 etype EType
Keith Randall67fdb0d2015-07-19 15:48:20 -07001011}
1012
1013var opToSSA = map[opAndType]ssa.Op{
David Chase997a9f32015-08-12 16:38:11 -04001014 opAndType{OADD, TINT8}: ssa.OpAdd8,
1015 opAndType{OADD, TUINT8}: ssa.OpAdd8,
1016 opAndType{OADD, TINT16}: ssa.OpAdd16,
1017 opAndType{OADD, TUINT16}: ssa.OpAdd16,
1018 opAndType{OADD, TINT32}: ssa.OpAdd32,
1019 opAndType{OADD, TUINT32}: ssa.OpAdd32,
1020 opAndType{OADD, TPTR32}: ssa.OpAdd32,
1021 opAndType{OADD, TINT64}: ssa.OpAdd64,
1022 opAndType{OADD, TUINT64}: ssa.OpAdd64,
1023 opAndType{OADD, TPTR64}: ssa.OpAdd64,
1024 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
1025 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001026
David Chase997a9f32015-08-12 16:38:11 -04001027 opAndType{OSUB, TINT8}: ssa.OpSub8,
1028 opAndType{OSUB, TUINT8}: ssa.OpSub8,
1029 opAndType{OSUB, TINT16}: ssa.OpSub16,
1030 opAndType{OSUB, TUINT16}: ssa.OpSub16,
1031 opAndType{OSUB, TINT32}: ssa.OpSub32,
1032 opAndType{OSUB, TUINT32}: ssa.OpSub32,
1033 opAndType{OSUB, TINT64}: ssa.OpSub64,
1034 opAndType{OSUB, TUINT64}: ssa.OpSub64,
1035 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
1036 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001037
Josh Bleecher Snydere61e7c92015-07-22 19:19:40 -07001038 opAndType{ONOT, TBOOL}: ssa.OpNot,
1039
David Chase3a9d0ac2015-08-28 14:24:10 -04001040 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
1041 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
1042 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
1043 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
1044 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
1045 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
1046 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
1047 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
1048 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
1049 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001050
Keith Randall4b803152015-07-29 17:07:09 -07001051 opAndType{OCOM, TINT8}: ssa.OpCom8,
1052 opAndType{OCOM, TUINT8}: ssa.OpCom8,
1053 opAndType{OCOM, TINT16}: ssa.OpCom16,
1054 opAndType{OCOM, TUINT16}: ssa.OpCom16,
1055 opAndType{OCOM, TINT32}: ssa.OpCom32,
1056 opAndType{OCOM, TUINT32}: ssa.OpCom32,
1057 opAndType{OCOM, TINT64}: ssa.OpCom64,
1058 opAndType{OCOM, TUINT64}: ssa.OpCom64,
1059
Josh Bleecher Snyderfa5fe192015-09-06 19:24:59 -07001060 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
1061 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
1062 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
1063 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
1064
David Chase997a9f32015-08-12 16:38:11 -04001065 opAndType{OMUL, TINT8}: ssa.OpMul8,
1066 opAndType{OMUL, TUINT8}: ssa.OpMul8,
1067 opAndType{OMUL, TINT16}: ssa.OpMul16,
1068 opAndType{OMUL, TUINT16}: ssa.OpMul16,
1069 opAndType{OMUL, TINT32}: ssa.OpMul32,
1070 opAndType{OMUL, TUINT32}: ssa.OpMul32,
1071 opAndType{OMUL, TINT64}: ssa.OpMul64,
1072 opAndType{OMUL, TUINT64}: ssa.OpMul64,
1073 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
1074 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
1075
1076 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
1077 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
Keith Randallbe1eb572015-07-22 13:46:15 -07001078
Todd Neal67cbd5b2015-08-18 19:14:47 -05001079 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
1080 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
1081 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
1082 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
1083 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
1084 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
1085
Todd Neala45f2d82015-08-17 17:46:06 -05001086 opAndType{ODIV, TINT8}: ssa.OpDiv8,
1087 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
1088 opAndType{ODIV, TINT16}: ssa.OpDiv16,
1089 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
1090 opAndType{ODIV, TINT32}: ssa.OpDiv32,
1091 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
1092 opAndType{ODIV, TINT64}: ssa.OpDiv64,
1093 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
1094
Todd Neal57d9e7e2015-08-18 19:51:44 -05001095 opAndType{OMOD, TINT8}: ssa.OpMod8,
1096 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1097 opAndType{OMOD, TINT16}: ssa.OpMod16,
1098 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1099 opAndType{OMOD, TINT32}: ssa.OpMod32,
1100 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1101 opAndType{OMOD, TINT64}: ssa.OpMod64,
1102 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1103
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001104 opAndType{OAND, TINT8}: ssa.OpAnd8,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001105 opAndType{OAND, TUINT8}: ssa.OpAnd8,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001106 opAndType{OAND, TINT16}: ssa.OpAnd16,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001107 opAndType{OAND, TUINT16}: ssa.OpAnd16,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001108 opAndType{OAND, TINT32}: ssa.OpAnd32,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001109 opAndType{OAND, TUINT32}: ssa.OpAnd32,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001110 opAndType{OAND, TINT64}: ssa.OpAnd64,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001111 opAndType{OAND, TUINT64}: ssa.OpAnd64,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001112
Alexandru Moșoi74024162015-07-29 17:52:25 +02001113 opAndType{OOR, TINT8}: ssa.OpOr8,
1114 opAndType{OOR, TUINT8}: ssa.OpOr8,
1115 opAndType{OOR, TINT16}: ssa.OpOr16,
1116 opAndType{OOR, TUINT16}: ssa.OpOr16,
1117 opAndType{OOR, TINT32}: ssa.OpOr32,
1118 opAndType{OOR, TUINT32}: ssa.OpOr32,
1119 opAndType{OOR, TINT64}: ssa.OpOr64,
1120 opAndType{OOR, TUINT64}: ssa.OpOr64,
1121
Alexandru Moșoi6d9362a12015-07-30 12:33:36 +02001122 opAndType{OXOR, TINT8}: ssa.OpXor8,
1123 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1124 opAndType{OXOR, TINT16}: ssa.OpXor16,
1125 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1126 opAndType{OXOR, TINT32}: ssa.OpXor32,
1127 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1128 opAndType{OXOR, TINT64}: ssa.OpXor64,
1129 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1130
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001131 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1132 opAndType{OEQ, TINT8}: ssa.OpEq8,
1133 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1134 opAndType{OEQ, TINT16}: ssa.OpEq16,
1135 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1136 opAndType{OEQ, TINT32}: ssa.OpEq32,
1137 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1138 opAndType{OEQ, TINT64}: ssa.OpEq64,
1139 opAndType{OEQ, TUINT64}: ssa.OpEq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001140 opAndType{OEQ, TINTER}: ssa.OpEqInter,
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07001141 opAndType{OEQ, TSLICE}: ssa.OpEqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001142 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1143 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1144 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001145 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001146 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1147 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001148 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1149 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001150
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001151 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1152 opAndType{ONE, TINT8}: ssa.OpNeq8,
1153 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1154 opAndType{ONE, TINT16}: ssa.OpNeq16,
1155 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1156 opAndType{ONE, TINT32}: ssa.OpNeq32,
1157 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1158 opAndType{ONE, TINT64}: ssa.OpNeq64,
1159 opAndType{ONE, TUINT64}: ssa.OpNeq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001160 opAndType{ONE, TINTER}: ssa.OpNeqInter,
Matthew Dempsky40f1d0c2016-04-18 14:02:08 -07001161 opAndType{ONE, TSLICE}: ssa.OpNeqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001162 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1163 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1164 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001165 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001166 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1167 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001168 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1169 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001170
David Chase8e601b22015-08-18 14:39:26 -04001171 opAndType{OLT, TINT8}: ssa.OpLess8,
1172 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1173 opAndType{OLT, TINT16}: ssa.OpLess16,
1174 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1175 opAndType{OLT, TINT32}: ssa.OpLess32,
1176 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1177 opAndType{OLT, TINT64}: ssa.OpLess64,
1178 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1179 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1180 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001181
David Chase8e601b22015-08-18 14:39:26 -04001182 opAndType{OGT, TINT8}: ssa.OpGreater8,
1183 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1184 opAndType{OGT, TINT16}: ssa.OpGreater16,
1185 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1186 opAndType{OGT, TINT32}: ssa.OpGreater32,
1187 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1188 opAndType{OGT, TINT64}: ssa.OpGreater64,
1189 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1190 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1191 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001192
David Chase8e601b22015-08-18 14:39:26 -04001193 opAndType{OLE, TINT8}: ssa.OpLeq8,
1194 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1195 opAndType{OLE, TINT16}: ssa.OpLeq16,
1196 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1197 opAndType{OLE, TINT32}: ssa.OpLeq32,
1198 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1199 opAndType{OLE, TINT64}: ssa.OpLeq64,
1200 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1201 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1202 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001203
David Chase8e601b22015-08-18 14:39:26 -04001204 opAndType{OGE, TINT8}: ssa.OpGeq8,
1205 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1206 opAndType{OGE, TINT16}: ssa.OpGeq16,
1207 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1208 opAndType{OGE, TINT32}: ssa.OpGeq32,
1209 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1210 opAndType{OGE, TINT64}: ssa.OpGeq64,
1211 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1212 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1213 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
David Chase40aba8c2015-08-05 22:11:14 -04001214
1215 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1216 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1217 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1218 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
Keith Randalla329e212015-09-12 13:26:57 -07001219
1220 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001221}
1222
Keith Randall4304fbc2015-11-16 13:20:16 -08001223func (s *state) concreteEtype(t *Type) EType {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001224 e := t.Etype
1225 switch e {
1226 default:
1227 return e
Keith Randall67fdb0d2015-07-19 15:48:20 -07001228 case TINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001229 if s.config.IntSize == 8 {
1230 return TINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001231 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001232 return TINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001233 case TUINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001234 if s.config.IntSize == 8 {
1235 return TUINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001236 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001237 return TUINT32
1238 case TUINTPTR:
1239 if s.config.PtrSize == 8 {
1240 return TUINT64
1241 }
1242 return TUINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001243 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001244}
1245
Keith Randall4304fbc2015-11-16 13:20:16 -08001246func (s *state) ssaOp(op Op, t *Type) ssa.Op {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001247 etype := s.concreteEtype(t)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001248 x, ok := opToSSA[opAndType{op, etype}]
1249 if !ok {
Josh Bleecher Snyderfca0f332016-04-22 08:39:56 -07001250 s.Unimplementedf("unhandled binary op %s %s", op, etype)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001251 }
1252 return x
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001253}
1254
David Chase3a9d0ac2015-08-28 14:24:10 -04001255func floatForComplex(t *Type) *Type {
1256 if t.Size() == 8 {
1257 return Types[TFLOAT32]
1258 } else {
1259 return Types[TFLOAT64]
1260 }
1261}
1262
Keith Randall4b803152015-07-29 17:07:09 -07001263type opAndTwoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001264 op Op
1265 etype1 EType
1266 etype2 EType
Keith Randall4b803152015-07-29 17:07:09 -07001267}
1268
David Chased052bbd2015-09-01 17:09:00 -04001269type twoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001270 etype1 EType
1271 etype2 EType
David Chased052bbd2015-09-01 17:09:00 -04001272}
1273
1274type twoOpsAndType struct {
1275 op1 ssa.Op
1276 op2 ssa.Op
Keith Randall4304fbc2015-11-16 13:20:16 -08001277 intermediateType EType
David Chased052bbd2015-09-01 17:09:00 -04001278}
1279
1280var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1281
1282 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1283 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1284 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1285 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1286
1287 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1288 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1289 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1290 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1291
1292 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1293 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1294 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1295 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1296
1297 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1298 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1299 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1300 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1301 // unsigned
1302 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1303 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1304 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1305 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1306
1307 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1308 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1309 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1310 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1311
1312 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1313 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1314 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1315 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1316
1317 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1318 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1319 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1320 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1321
1322 // float
1323 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1324 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1325 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1326 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1327}
1328
Keith Randall4b803152015-07-29 17:07:09 -07001329var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1330 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1331 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1332 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1333 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1334 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1335 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1336 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1337 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1338
1339 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1340 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1341 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1342 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1343 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1344 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1345 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1346 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1347
1348 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1349 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1350 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1351 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1352 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1353 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1354 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1355 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1356
1357 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1358 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1359 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1360 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1361 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1362 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1363 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1364 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1365
1366 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1367 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1368 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1369 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1370 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1371 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1372 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1373 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1374
1375 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1376 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1377 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1378 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1379 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1380 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1381 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1382 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1383
1384 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1385 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1386 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1387 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1388 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1389 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1390 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1391 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1392
1393 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1394 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1395 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1396 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1397 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1398 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1399 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1400 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1401}
1402
Keith Randall4304fbc2015-11-16 13:20:16 -08001403func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
Keith Randall4b803152015-07-29 17:07:09 -07001404 etype1 := s.concreteEtype(t)
1405 etype2 := s.concreteEtype(u)
1406 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1407 if !ok {
Josh Bleecher Snyderfca0f332016-04-22 08:39:56 -07001408 s.Unimplementedf("unhandled shift op %s etype=%s/%s", op, etype1, etype2)
Keith Randall4b803152015-07-29 17:07:09 -07001409 }
1410 return x
1411}
1412
Keith Randall4304fbc2015-11-16 13:20:16 -08001413func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
David Chase40aba8c2015-08-05 22:11:14 -04001414 etype1 := s.concreteEtype(t)
1415 x, ok := opToSSA[opAndType{op, etype1}]
1416 if !ok {
Josh Bleecher Snyderfca0f332016-04-22 08:39:56 -07001417 s.Unimplementedf("unhandled rotate op %s etype=%s", op, etype1)
David Chase40aba8c2015-08-05 22:11:14 -04001418 }
1419 return x
1420}
1421
Keith Randalld2fd43a2015-04-15 15:51:25 -07001422// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -07001423func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -04001424 s.pushLine(n.Lineno)
1425 defer s.popLine()
1426
Keith Randall06f32922015-07-11 11:39:12 -07001427 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001428 switch n.Op {
Todd Nealdef7c652015-09-07 19:07:02 -05001429 case OCFUNC:
Todd Neald076ef72015-10-15 20:25:32 -05001430 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
Todd Nealdef7c652015-09-07 19:07:02 -05001431 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
David Chase956f3192015-09-11 16:40:05 -04001432 case OPARAM:
David Chase57670ad2015-10-09 16:48:30 -04001433 addr := s.addr(n, false)
David Chase32ffbf72015-10-08 17:14:12 -04001434 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001435 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07001436 if n.Class == PFUNC {
1437 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -07001438 sym := funcsym(n.Sym)
1439 aux := &ssa.ExternSymbol{n.Type, sym}
1440 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -07001441 }
Keith Randall6a8a9da2016-02-27 17:49:31 -08001442 if s.canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -07001443 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -07001444 }
David Chase57670ad2015-10-09 16:48:30 -04001445 addr := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001446 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
David Chase956f3192015-09-11 16:40:05 -04001447 case OCLOSUREVAR:
David Chase57670ad2015-10-09 16:48:30 -04001448 addr := s.addr(n, false)
David Chase956f3192015-09-11 16:40:05 -04001449 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001450 case OLITERAL:
Matthew Dempsky97360092016-04-22 12:27:29 -07001451 switch u := n.Val().U.(type) {
1452 case *Mpint:
1453 i := u.Int64()
Keith Randall9cb332e2015-07-28 14:19:20 -07001454 switch n.Type.Size() {
1455 case 1:
1456 return s.constInt8(n.Type, int8(i))
1457 case 2:
1458 return s.constInt16(n.Type, int16(i))
1459 case 4:
1460 return s.constInt32(n.Type, int32(i))
1461 case 8:
1462 return s.constInt64(n.Type, i)
1463 default:
1464 s.Fatalf("bad integer size %d", n.Type.Size())
1465 return nil
1466 }
Matthew Dempsky97360092016-04-22 12:27:29 -07001467 case string:
1468 if u == "" {
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001469 return s.constEmptyString(n.Type)
1470 }
Matthew Dempsky97360092016-04-22 12:27:29 -07001471 return s.entryNewValue0A(ssa.OpConstString, n.Type, u)
1472 case bool:
1473 v := s.constBool(u)
Keith Randallb5c5efd2016-01-14 16:02:23 -08001474 // For some reason the frontend gets the line numbers of
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001475 // CTBOOL literals totally wrong. Fix it here by grabbing
Keith Randallb5c5efd2016-01-14 16:02:23 -08001476 // the line number of the enclosing AST node.
1477 if len(s.line) >= 2 {
1478 v.Line = s.line[len(s.line)-2]
1479 }
1480 return v
Matthew Dempsky97360092016-04-22 12:27:29 -07001481 case *NilVal:
Keith Randall9f954db2015-08-18 10:26:28 -07001482 t := n.Type
1483 switch {
1484 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001485 return s.constSlice(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001486 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001487 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001488 default:
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001489 return s.constNil(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001490 }
Matthew Dempsky97360092016-04-22 12:27:29 -07001491 case *Mpflt:
David Chase997a9f32015-08-12 16:38:11 -04001492 switch n.Type.Size() {
1493 case 4:
Matthew Dempsky97360092016-04-22 12:27:29 -07001494 return s.constFloat32(n.Type, u.Float32())
David Chase997a9f32015-08-12 16:38:11 -04001495 case 8:
Matthew Dempsky97360092016-04-22 12:27:29 -07001496 return s.constFloat64(n.Type, u.Float64())
David Chase997a9f32015-08-12 16:38:11 -04001497 default:
1498 s.Fatalf("bad float size %d", n.Type.Size())
1499 return nil
1500 }
Matthew Dempsky97360092016-04-22 12:27:29 -07001501 case *Mpcplx:
1502 r := &u.Real
1503 i := &u.Imag
David Chase52578582015-08-28 14:24:10 -04001504 switch n.Type.Size() {
1505 case 8:
Matthew Dempsky97360092016-04-22 12:27:29 -07001506 pt := Types[TFLOAT32]
1507 return s.newValue2(ssa.OpComplexMake, n.Type,
1508 s.constFloat32(pt, r.Float32()),
1509 s.constFloat32(pt, i.Float32()))
David Chase52578582015-08-28 14:24:10 -04001510 case 16:
Matthew Dempsky97360092016-04-22 12:27:29 -07001511 pt := Types[TFLOAT64]
1512 return s.newValue2(ssa.OpComplexMake, n.Type,
1513 s.constFloat64(pt, r.Float64()),
1514 s.constFloat64(pt, i.Float64()))
David Chase52578582015-08-28 14:24:10 -04001515 default:
1516 s.Fatalf("bad float size %d", n.Type.Size())
1517 return nil
1518 }
David Chase997a9f32015-08-12 16:38:11 -04001519
Keith Randalld2fd43a2015-04-15 15:51:25 -07001520 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001521 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001522 return nil
1523 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001524 case OCONVNOP:
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001525 to := n.Type
1526 from := n.Left.Type
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001527
1528 // Assume everything will work out, so set up our return value.
1529 // Anything interesting that happens from here is a fatal.
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001530 x := s.expr(n.Left)
David Chasee99dd522015-10-19 11:36:07 -04001531
1532 // Special case for not confusing GC and liveness.
1533 // We don't want pointers accidentally classified
1534 // as not-pointers or vice-versa because of copy
1535 // elision.
Matthew Dempsky788f1122016-03-28 10:55:44 -07001536 if to.IsPtrShaped() != from.IsPtrShaped() {
Keith Randall7807bda2015-11-10 15:35:36 -08001537 return s.newValue2(ssa.OpConvert, to, x, s.mem())
David Chasee99dd522015-10-19 11:36:07 -04001538 }
1539
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001540 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1541
Todd Nealdef7c652015-09-07 19:07:02 -05001542 // CONVNOP closure
Matthew Dempsky788f1122016-03-28 10:55:44 -07001543 if to.Etype == TFUNC && from.IsPtrShaped() {
Todd Nealdef7c652015-09-07 19:07:02 -05001544 return v
1545 }
1546
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001547 // named <--> unnamed type or typed <--> untyped const
1548 if from.Etype == to.Etype {
1549 return v
1550 }
David Chasee99dd522015-10-19 11:36:07 -04001551
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001552 // unsafe.Pointer <--> *T
1553 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1554 return v
1555 }
1556
1557 dowidth(from)
1558 dowidth(to)
1559 if from.Width != to.Width {
1560 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1561 return nil
1562 }
1563 if etypesign(from.Etype) != etypesign(to.Etype) {
Josh Bleecher Snyderfca0f332016-04-22 08:39:56 -07001564 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, from.Etype, to, to.Etype)
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001565 return nil
1566 }
1567
Ian Lance Taylor88e18032016-03-01 15:17:34 -08001568 if instrumenting {
David Chase57670ad2015-10-09 16:48:30 -04001569 // These appear to be fine, but they fail the
1570 // integer constraint below, so okay them here.
1571 // Sample non-integer conversion: map[string]string -> *uint8
1572 return v
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001573 }
1574
1575 if etypesign(from.Etype) == 0 {
1576 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1577 return nil
1578 }
1579
1580 // integer, same width, same sign
1581 return v
1582
Michael Matloob73054f52015-06-14 11:38:46 -07001583 case OCONV:
1584 x := s.expr(n.Left)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001585 ft := n.Left.Type // from type
1586 tt := n.Type // to type
1587 if ft.IsInteger() && tt.IsInteger() {
1588 var op ssa.Op
1589 if tt.Size() == ft.Size() {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001590 op = ssa.OpCopy
Keith Randall2a5e6c42015-07-23 14:35:02 -07001591 } else if tt.Size() < ft.Size() {
1592 // truncation
1593 switch 10*ft.Size() + tt.Size() {
1594 case 21:
1595 op = ssa.OpTrunc16to8
1596 case 41:
1597 op = ssa.OpTrunc32to8
1598 case 42:
1599 op = ssa.OpTrunc32to16
1600 case 81:
1601 op = ssa.OpTrunc64to8
1602 case 82:
1603 op = ssa.OpTrunc64to16
1604 case 84:
1605 op = ssa.OpTrunc64to32
1606 default:
1607 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1608 }
1609 } else if ft.IsSigned() {
1610 // sign extension
1611 switch 10*ft.Size() + tt.Size() {
1612 case 12:
1613 op = ssa.OpSignExt8to16
1614 case 14:
1615 op = ssa.OpSignExt8to32
1616 case 18:
1617 op = ssa.OpSignExt8to64
1618 case 24:
1619 op = ssa.OpSignExt16to32
1620 case 28:
1621 op = ssa.OpSignExt16to64
1622 case 48:
1623 op = ssa.OpSignExt32to64
1624 default:
1625 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1626 }
1627 } else {
1628 // zero extension
1629 switch 10*ft.Size() + tt.Size() {
1630 case 12:
1631 op = ssa.OpZeroExt8to16
1632 case 14:
1633 op = ssa.OpZeroExt8to32
1634 case 18:
1635 op = ssa.OpZeroExt8to64
1636 case 24:
1637 op = ssa.OpZeroExt16to32
1638 case 28:
1639 op = ssa.OpZeroExt16to64
1640 case 48:
1641 op = ssa.OpZeroExt32to64
1642 default:
1643 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1644 }
1645 }
1646 return s.newValue1(op, n.Type, x)
1647 }
David Chase42825882015-08-20 15:14:20 -04001648
David Chased052bbd2015-09-01 17:09:00 -04001649 if ft.IsFloat() || tt.IsFloat() {
1650 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1651 if !ok {
1652 s.Fatalf("weird float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001653 }
David Chased052bbd2015-09-01 17:09:00 -04001654 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1655
1656 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1657 // normal case, not tripping over unsigned 64
1658 if op1 == ssa.OpCopy {
1659 if op2 == ssa.OpCopy {
1660 return x
1661 }
1662 return s.newValue1(op2, n.Type, x)
1663 }
1664 if op2 == ssa.OpCopy {
1665 return s.newValue1(op1, n.Type, x)
1666 }
1667 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1668 }
1669 // Tricky 64-bit unsigned cases.
1670 if ft.IsInteger() {
1671 // therefore tt is float32 or float64, and ft is also unsigned
David Chase42825882015-08-20 15:14:20 -04001672 if tt.Size() == 4 {
1673 return s.uint64Tofloat32(n, x, ft, tt)
1674 }
1675 if tt.Size() == 8 {
1676 return s.uint64Tofloat64(n, x, ft, tt)
1677 }
David Chased052bbd2015-09-01 17:09:00 -04001678 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001679 }
David Chased052bbd2015-09-01 17:09:00 -04001680 // therefore ft is float32 or float64, and tt is unsigned integer
David Chase73151062015-08-26 14:25:40 -04001681 if ft.Size() == 4 {
David Chased052bbd2015-09-01 17:09:00 -04001682 return s.float32ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001683 }
David Chased052bbd2015-09-01 17:09:00 -04001684 if ft.Size() == 8 {
1685 return s.float64ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001686 }
David Chased052bbd2015-09-01 17:09:00 -04001687 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1688 return nil
David Chase42825882015-08-20 15:14:20 -04001689 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001690
1691 if ft.IsComplex() && tt.IsComplex() {
1692 var op ssa.Op
1693 if ft.Size() == tt.Size() {
1694 op = ssa.OpCopy
1695 } else if ft.Size() == 8 && tt.Size() == 16 {
1696 op = ssa.OpCvt32Fto64F
1697 } else if ft.Size() == 16 && tt.Size() == 8 {
1698 op = ssa.OpCvt64Fto32F
1699 } else {
1700 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1701 }
1702 ftp := floatForComplex(ft)
1703 ttp := floatForComplex(tt)
1704 return s.newValue2(ssa.OpComplexMake, tt,
1705 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1706 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1707 }
David Chase42825882015-08-20 15:14:20 -04001708
Josh Bleecher Snyderfca0f332016-04-22 08:39:56 -07001709 s.Unimplementedf("unhandled OCONV %s -> %s", n.Left.Type.Etype, n.Type.Etype)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001710 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001711
Keith Randall269baa92015-09-17 10:31:16 -07001712 case ODOTTYPE:
1713 res, _ := s.dottype(n, false)
1714 return res
1715
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001716 // binary ops
1717 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001718 a := s.expr(n.Left)
1719 b := s.expr(n.Right)
Keith Randalldb380bf2015-09-10 11:05:42 -07001720 if n.Left.Type.IsComplex() {
Keith Randallc244ce02015-09-10 14:59:00 -07001721 pt := floatForComplex(n.Left.Type)
Keith Randalldb380bf2015-09-10 11:05:42 -07001722 op := s.ssaOp(OEQ, pt)
1723 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1724 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1725 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1726 switch n.Op {
1727 case OEQ:
1728 return c
1729 case ONE:
1730 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1731 default:
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -07001732 s.Fatalf("ordered complex compare %s", n.Op)
Keith Randalldb380bf2015-09-10 11:05:42 -07001733 }
Keith Randalldb380bf2015-09-10 11:05:42 -07001734 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001735 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
David Chase3a9d0ac2015-08-28 14:24:10 -04001736 case OMUL:
1737 a := s.expr(n.Left)
1738 b := s.expr(n.Right)
1739 if n.Type.IsComplex() {
1740 mulop := ssa.OpMul64F
1741 addop := ssa.OpAdd64F
1742 subop := ssa.OpSub64F
1743 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1744 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1745
1746 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1747 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1748 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1749 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1750
1751 if pt != wt { // Widen for calculation
1752 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1753 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1754 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1755 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1756 }
1757
1758 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1759 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1760
1761 if pt != wt { // Narrow to store back
1762 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1763 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1764 }
1765
1766 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1767 }
1768 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1769
1770 case ODIV:
1771 a := s.expr(n.Left)
1772 b := s.expr(n.Right)
1773 if n.Type.IsComplex() {
1774 // TODO this is not executed because the front-end substitutes a runtime call.
1775 // That probably ought to change; with modest optimization the widen/narrow
1776 // conversions could all be elided in larger expression trees.
1777 mulop := ssa.OpMul64F
1778 addop := ssa.OpAdd64F
1779 subop := ssa.OpSub64F
1780 divop := ssa.OpDiv64F
1781 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1782 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1783
1784 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1785 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1786 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1787 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1788
1789 if pt != wt { // Widen for calculation
1790 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1791 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1792 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1793 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1794 }
1795
1796 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1797 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1798 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1799
1800 // TODO not sure if this is best done in wide precision or narrow
1801 // Double-rounding might be an issue.
1802 // Note that the pre-SSA implementation does the entire calculation
1803 // in wide format, so wide is compatible.
1804 xreal = s.newValue2(divop, wt, xreal, denom)
1805 ximag = s.newValue2(divop, wt, ximag, denom)
1806
1807 if pt != wt { // Narrow to store back
1808 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1809 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1810 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001811 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1812 }
David Chase18559e22015-10-28 13:55:46 -04001813 if n.Type.IsFloat() {
1814 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1815 } else {
1816 // do a size-appropriate check for zero
1817 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1818 s.check(cmp, panicdivide)
1819 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1820 }
1821 case OMOD:
1822 a := s.expr(n.Left)
1823 b := s.expr(n.Right)
1824 // do a size-appropriate check for zero
1825 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1826 s.check(cmp, panicdivide)
David Chase3a9d0ac2015-08-28 14:24:10 -04001827 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1828 case OADD, OSUB:
1829 a := s.expr(n.Left)
1830 b := s.expr(n.Right)
1831 if n.Type.IsComplex() {
1832 pt := floatForComplex(n.Type)
1833 op := s.ssaOp(n.Op, pt)
1834 return s.newValue2(ssa.OpComplexMake, n.Type,
1835 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1836 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1837 }
1838 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
David Chase18559e22015-10-28 13:55:46 -04001839 case OAND, OOR, OHMUL, OXOR:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001840 a := s.expr(n.Left)
1841 b := s.expr(n.Right)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001842 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
Keith Randall4b803152015-07-29 17:07:09 -07001843 case OLSH, ORSH:
1844 a := s.expr(n.Left)
1845 b := s.expr(n.Right)
1846 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
David Chase40aba8c2015-08-05 22:11:14 -04001847 case OLROT:
1848 a := s.expr(n.Left)
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001849 i := n.Right.Int64()
David Chase40aba8c2015-08-05 22:11:14 -04001850 if i <= 0 || i >= n.Type.Size()*8 {
1851 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1852 }
1853 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001854 case OANDAND, OOROR:
1855 // To implement OANDAND (and OOROR), we introduce a
1856 // new temporary variable to hold the result. The
1857 // variable is associated with the OANDAND node in the
1858 // s.vars table (normally variables are only
1859 // associated with ONAME nodes). We convert
1860 // A && B
1861 // to
1862 // var = A
1863 // if var {
1864 // var = B
1865 // }
1866 // Using var in the subsequent block introduces the
1867 // necessary phi variable.
1868 el := s.expr(n.Left)
1869 s.vars[n] = el
1870
1871 b := s.endBlock()
1872 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07001873 b.SetControl(el)
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07001874 // In theory, we should set b.Likely here based on context.
1875 // However, gc only gives us likeliness hints
1876 // in a single place, for plain OIF statements,
1877 // and passing around context is finnicky, so don't bother for now.
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001878
1879 bRight := s.f.NewBlock(ssa.BlockPlain)
1880 bResult := s.f.NewBlock(ssa.BlockPlain)
1881 if n.Op == OANDAND {
Todd Neal47d67992015-08-28 21:36:29 -05001882 b.AddEdgeTo(bRight)
1883 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001884 } else if n.Op == OOROR {
Todd Neal47d67992015-08-28 21:36:29 -05001885 b.AddEdgeTo(bResult)
1886 b.AddEdgeTo(bRight)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001887 }
1888
1889 s.startBlock(bRight)
1890 er := s.expr(n.Right)
1891 s.vars[n] = er
1892
1893 b = s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05001894 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001895
1896 s.startBlock(bResult)
Josh Bleecher Snyder35ad1fc2015-08-27 10:11:08 -07001897 return s.variable(n, Types[TBOOL])
Keith Randall7e390722015-09-12 14:14:02 -07001898 case OCOMPLEX:
1899 r := s.expr(n.Left)
1900 i := s.expr(n.Right)
1901 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001902
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001903 // unary ops
David Chase3a9d0ac2015-08-28 14:24:10 -04001904 case OMINUS:
1905 a := s.expr(n.Left)
1906 if n.Type.IsComplex() {
1907 tp := floatForComplex(n.Type)
1908 negop := s.ssaOp(n.Op, tp)
1909 return s.newValue2(ssa.OpComplexMake, n.Type,
1910 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1911 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1912 }
1913 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randalla329e212015-09-12 13:26:57 -07001914 case ONOT, OCOM, OSQRT:
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001915 a := s.expr(n.Left)
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001916 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randall2f518072015-09-10 11:37:09 -07001917 case OIMAG, OREAL:
1918 a := s.expr(n.Left)
1919 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001920 case OPLUS:
1921 return s.expr(n.Left)
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001922
Keith Randallcfc2aa52015-05-18 16:44:20 -07001923 case OADDR:
David Chase57670ad2015-10-09 16:48:30 -04001924 return s.addr(n.Left, n.Bounded)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001925
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07001926 case OINDREG:
1927 if int(n.Reg) != Thearch.REGSP {
1928 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1929 return nil
1930 }
1931 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1932 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1933
Keith Randalld2fd43a2015-04-15 15:51:25 -07001934 case OIND:
Keith Randall3c1a4c12016-04-19 21:06:53 -07001935 p := s.exprPtr(n.Left, false, n.Lineno)
Keith Randall8f22b522015-06-11 21:29:25 -07001936 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001937
Keith Randallcd7e0592015-07-15 21:33:49 -07001938 case ODOT:
Keith Randalla734bbc2016-01-11 21:05:33 -08001939 t := n.Left.Type
1940 if canSSAType(t) {
1941 v := s.expr(n.Left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07001942 return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
Keith Randalla734bbc2016-01-11 21:05:33 -08001943 }
David Chase57670ad2015-10-09 16:48:30 -04001944 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001945 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcd7e0592015-07-15 21:33:49 -07001946
Keith Randalld2fd43a2015-04-15 15:51:25 -07001947 case ODOTPTR:
Keith Randall3c1a4c12016-04-19 21:06:53 -07001948 p := s.exprPtr(n.Left, false, n.Lineno)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001949 p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
Keith Randall8f22b522015-06-11 21:29:25 -07001950 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001951
1952 case OINDEX:
Keith Randall97035642015-10-09 09:33:29 -07001953 switch {
1954 case n.Left.Type.IsString():
Keith Randallcfc2aa52015-05-18 16:44:20 -07001955 a := s.expr(n.Left)
1956 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001957 i = s.extendIndex(i)
Keith Randall97035642015-10-09 09:33:29 -07001958 if !n.Bounded {
1959 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1960 s.boundsCheck(i, len)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07001961 }
Keith Randall97035642015-10-09 09:33:29 -07001962 ptrtyp := Ptrto(Types[TUINT8])
1963 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001964 if Isconst(n.Right, CTINT) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001965 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001966 } else {
1967 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1968 }
Keith Randall97035642015-10-09 09:33:29 -07001969 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1970 case n.Left.Type.IsSlice():
David Chase57670ad2015-10-09 16:48:30 -04001971 p := s.addr(n, false)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001972 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001973 case n.Left.Type.IsArray():
1974 // TODO: fix when we can SSA arrays of length 1.
David Chase57670ad2015-10-09 16:48:30 -04001975 p := s.addr(n, false)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001976 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001977 default:
1978 s.Fatalf("bad type for index %v", n.Left.Type)
1979 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001980 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07001981
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001982 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001983 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001984 case n.Left.Type.IsSlice():
1985 op := ssa.OpSliceLen
1986 if n.Op == OCAP {
1987 op = ssa.OpSliceCap
1988 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001989 return s.newValue1(op, Types[TINT], s.expr(n.Left))
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001990 case n.Left.Type.IsString(): // string; not reachable for OCAP
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001991 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
Todd Neal707af252015-08-28 15:56:43 -05001992 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1993 return s.referenceTypeBuiltin(n, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001994 default: // array
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001995 return s.constInt(Types[TINT], n.Left.Type.NumElem())
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001996 }
1997
Josh Bleecher Snydera2d15802015-08-12 10:12:14 -07001998 case OSPTR:
1999 a := s.expr(n.Left)
2000 if n.Left.Type.IsSlice() {
2001 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
2002 } else {
2003 return s.newValue1(ssa.OpStringPtr, n.Type, a)
2004 }
2005
Keith Randalld1c15a02015-08-04 15:47:22 -07002006 case OITAB:
2007 a := s.expr(n.Left)
2008 return s.newValue1(ssa.OpITab, n.Type, a)
2009
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07002010 case OEFACE:
2011 tab := s.expr(n.Left)
2012 data := s.expr(n.Right)
Keith Randall808d7c72015-10-07 14:35:25 -07002013 // The frontend allows putting things like struct{*byte} in
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002014 // the data portion of an eface. But we don't want struct{*byte}
Keith Randall808d7c72015-10-07 14:35:25 -07002015 // as a register type because (among other reasons) the liveness
2016 // analysis is confused by the "fat" variables that result from
2017 // such types being spilled.
2018 // So here we ensure that we are selecting the underlying pointer
2019 // when we build an eface.
Keith Randalla734bbc2016-01-11 21:05:33 -08002020 // TODO: get rid of this now that structs can be SSA'd?
Matthew Dempsky788f1122016-03-28 10:55:44 -07002021 for !data.Type.IsPtrShaped() {
Keith Randall808d7c72015-10-07 14:35:25 -07002022 switch {
2023 case data.Type.IsArray():
Matthew Dempsky0b281872016-03-10 14:35:39 -08002024 data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
Keith Randall808d7c72015-10-07 14:35:25 -07002025 case data.Type.IsStruct():
2026 for i := data.Type.NumFields() - 1; i >= 0; i-- {
2027 f := data.Type.FieldType(i)
2028 if f.Size() == 0 {
2029 // eface type could also be struct{p *byte; q [0]int}
2030 continue
2031 }
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002032 data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
Keith Randall808d7c72015-10-07 14:35:25 -07002033 break
2034 }
2035 default:
2036 s.Fatalf("type being put into an eface isn't a pointer")
2037 }
2038 }
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07002039 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
2040
Keith Randall5505e8c2015-09-12 23:27:26 -07002041 case OSLICE, OSLICEARR:
2042 v := s.expr(n.Left)
2043 var i, j *ssa.Value
2044 if n.Right.Left != nil {
2045 i = s.extendIndex(s.expr(n.Right.Left))
2046 }
2047 if n.Right.Right != nil {
2048 j = s.extendIndex(s.expr(n.Right.Right))
2049 }
2050 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
2051 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07002052 case OSLICESTR:
Keith Randall5505e8c2015-09-12 23:27:26 -07002053 v := s.expr(n.Left)
2054 var i, j *ssa.Value
2055 if n.Right.Left != nil {
2056 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07002057 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002058 if n.Right.Right != nil {
2059 j = s.extendIndex(s.expr(n.Right.Right))
Keith Randall3526cf52015-08-24 23:52:03 -07002060 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002061 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
2062 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
2063 case OSLICE3, OSLICE3ARR:
2064 v := s.expr(n.Left)
2065 var i *ssa.Value
2066 if n.Right.Left != nil {
2067 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07002068 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002069 j := s.extendIndex(s.expr(n.Right.Right.Left))
2070 k := s.extendIndex(s.expr(n.Right.Right.Right))
2071 p, l, c := s.slice(n.Left.Type, v, i, j, k)
2072 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07002073
David Chase8eec2bb2016-03-11 00:10:52 -05002074 case OCALLFUNC:
2075 if isIntrinsicCall1(n) {
2076 return s.intrinsicCall1(n)
2077 }
2078 fallthrough
2079
2080 case OCALLINTER, OCALLMETH:
Keith Randall5ba31942016-01-25 17:06:54 -08002081 a := s.call(n, callNormal)
2082 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002083
2084 case OGETG:
Keith Randalld694f832015-10-19 18:54:40 -07002085 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002086
Keith Randall9d22c102015-09-11 11:02:57 -07002087 case OAPPEND:
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002088 return s.append(n, false)
Keith Randall9d22c102015-09-11 11:02:57 -07002089
Keith Randalld2fd43a2015-04-15 15:51:25 -07002090 default:
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -07002091 s.Unimplementedf("unhandled expr %s", n.Op)
Keith Randalld2fd43a2015-04-15 15:51:25 -07002092 return nil
2093 }
2094}
2095
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002096// append converts an OAPPEND node to SSA.
2097// If inplace is false, it converts the OAPPEND expression n to an ssa.Value,
2098// adds it to s, and returns the Value.
2099// If inplace is true, it writes the result of the OAPPEND expression n
2100// back to the slice being appended to, and returns nil.
2101// inplace MUST be set to false if the slice can be SSA'd.
2102func (s *state) append(n *Node, inplace bool) *ssa.Value {
2103 // If inplace is false, process as expression "append(s, e1, e2, e3)":
2104 //
Josh Bleecher Snyder6b33b0e2016-04-10 09:08:00 -07002105 // ptr, len, cap := s
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002106 // newlen := len + 3
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002107 // if newlen > cap {
Josh Bleecher Snyder6b33b0e2016-04-10 09:08:00 -07002108 // ptr, len, cap = growslice(s, newlen)
2109 // newlen = len + 3 // recalculate to avoid a spill
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002110 // }
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002111 // // with write barriers, if needed:
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002112 // *(ptr+len) = e1
2113 // *(ptr+len+1) = e2
2114 // *(ptr+len+2) = e3
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002115 // return makeslice(ptr, newlen, cap)
2116 //
2117 //
2118 // If inplace is true, process as statement "s = append(s, e1, e2, e3)":
2119 //
2120 // a := &s
2121 // ptr, len, cap := s
2122 // newlen := len + 3
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002123 // if newlen > cap {
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002124 // newptr, len, newcap = growslice(ptr, len, cap, newlen)
2125 // vardef(a) // if necessary, advise liveness we are writing a new a
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002126 // *a.cap = newcap // write before ptr to avoid a spill
2127 // *a.ptr = newptr // with write barrier
2128 // }
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002129 // newlen = len + 3 // recalculate to avoid a spill
2130 // *a.len = newlen
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002131 // // with write barriers, if needed:
2132 // *(ptr+len) = e1
2133 // *(ptr+len+1) = e2
2134 // *(ptr+len+2) = e3
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002135
2136 et := n.Type.Elem()
2137 pt := Ptrto(et)
2138
2139 // Evaluate slice
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002140 sn := n.List.First() // the slice node is the first in the list
2141
2142 var slice, addr *ssa.Value
2143 if inplace {
2144 addr = s.addr(sn, false)
2145 slice = s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
2146 } else {
2147 slice = s.expr(sn)
2148 }
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002149
2150 // Allocate new blocks
2151 grow := s.f.NewBlock(ssa.BlockPlain)
2152 assign := s.f.NewBlock(ssa.BlockPlain)
2153
2154 // Decide if we need to grow
2155 nargs := int64(n.List.Len() - 1)
2156 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2157 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2158 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2159 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002160
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002161 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
2162 s.vars[&ptrVar] = p
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002163
2164 if !inplace {
2165 s.vars[&newlenVar] = nl
2166 s.vars[&capVar] = c
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002167 } else {
2168 s.vars[&lenVar] = l
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002169 }
2170
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002171 b := s.endBlock()
2172 b.Kind = ssa.BlockIf
2173 b.Likely = ssa.BranchUnlikely
2174 b.SetControl(cmp)
2175 b.AddEdgeTo(grow)
2176 b.AddEdgeTo(assign)
2177
2178 // Call growslice
2179 s.startBlock(grow)
Keith Randallbfe0cbd2016-04-19 15:38:59 -07002180 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type.Elem())}, s.sb)
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002181
2182 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
2183
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002184 if inplace {
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002185 if sn.Op == ONAME {
2186 // Tell liveness we're about to build a new slice
2187 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, sn, s.mem())
2188 }
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002189 capaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_cap), addr)
2190 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capaddr, r[2], s.mem())
2191 s.insertWBstore(pt, addr, r[0], n.Lineno, 0)
2192 // load the value we just stored to avoid having to spill it
2193 s.vars[&ptrVar] = s.newValue2(ssa.OpLoad, pt, addr, s.mem())
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002194 s.vars[&lenVar] = r[1] // avoid a spill in the fast path
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002195 } else {
2196 s.vars[&ptrVar] = r[0]
2197 s.vars[&newlenVar] = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], r[1], s.constInt(Types[TINT], nargs))
2198 s.vars[&capVar] = r[2]
2199 }
2200
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002201 b = s.endBlock()
2202 b.AddEdgeTo(assign)
2203
2204 // assign new elements to slots
2205 s.startBlock(assign)
2206
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002207 if inplace {
2208 l = s.variable(&lenVar, Types[TINT]) // generates phi for len
2209 nl = s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2210 lenaddr := s.newValue1I(ssa.OpOffPtr, pt, int64(Array_nel), addr)
2211 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenaddr, nl, s.mem())
2212 }
2213
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002214 // Evaluate args
2215 args := make([]*ssa.Value, 0, nargs)
2216 store := make([]bool, 0, nargs)
2217 for _, n := range n.List.Slice()[1:] {
2218 if canSSAType(n.Type) {
2219 args = append(args, s.expr(n))
2220 store = append(store, true)
2221 } else {
2222 args = append(args, s.addr(n, false))
2223 store = append(store, false)
2224 }
2225 }
2226
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002227 p = s.variable(&ptrVar, pt) // generates phi for ptr
2228 if !inplace {
2229 nl = s.variable(&newlenVar, Types[TINT]) // generates phi for nl
2230 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
2231 }
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002232 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
2233 // TODO: just one write barrier call for all of these writes?
2234 // TODO: maybe just one writeBarrier.enabled check?
2235 for i, arg := range args {
2236 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
2237 if store[i] {
2238 if haspointers(et) {
2239 s.insertWBstore(et, addr, arg, n.Lineno, 0)
2240 } else {
2241 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2242 }
2243 } else {
2244 if haspointers(et) {
2245 s.insertWBmove(et, addr, arg, n.Lineno)
2246 } else {
2247 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2248 }
2249 }
2250 }
2251
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002252 delete(s.vars, &ptrVar)
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002253 if inplace {
Josh Bleecher Snyder03e216f2016-04-18 09:40:30 -07002254 delete(s.vars, &lenVar)
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002255 return nil
2256 }
Josh Bleecher Snyder6b33b0e2016-04-10 09:08:00 -07002257 delete(s.vars, &newlenVar)
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002258 delete(s.vars, &capVar)
Josh Bleecher Snydera4650a22016-04-10 09:44:17 -07002259 // make result
Josh Bleecher Snyder5e1b7bd2016-04-04 10:58:21 -07002260 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
2261}
2262
Keith Randall99187312015-11-02 16:56:53 -08002263// condBranch evaluates the boolean expression cond and branches to yes
2264// if cond is true and no if cond is false.
2265// This function is intended to handle && and || better than just calling
2266// s.expr(cond) and branching on the result.
2267func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2268 if cond.Op == OANDAND {
2269 mid := s.f.NewBlock(ssa.BlockPlain)
2270 s.stmtList(cond.Ninit)
2271 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2272 s.startBlock(mid)
2273 s.condBranch(cond.Right, yes, no, likely)
2274 return
2275 // Note: if likely==1, then both recursive calls pass 1.
2276 // If likely==-1, then we don't have enough information to decide
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002277 // whether the first branch is likely or not. So we pass 0 for
Keith Randall99187312015-11-02 16:56:53 -08002278 // the likeliness of the first branch.
2279 // TODO: have the frontend give us branch prediction hints for
2280 // OANDAND and OOROR nodes (if it ever has such info).
2281 }
2282 if cond.Op == OOROR {
2283 mid := s.f.NewBlock(ssa.BlockPlain)
2284 s.stmtList(cond.Ninit)
2285 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2286 s.startBlock(mid)
2287 s.condBranch(cond.Right, yes, no, likely)
2288 return
2289 // Note: if likely==-1, then both recursive calls pass -1.
2290 // If likely==1, then we don't have enough info to decide
2291 // the likelihood of the first branch.
2292 }
Keith Randalld19bfc32015-11-03 09:30:17 -08002293 if cond.Op == ONOT {
2294 s.stmtList(cond.Ninit)
2295 s.condBranch(cond.Left, no, yes, -likely)
2296 return
2297 }
Keith Randall99187312015-11-02 16:56:53 -08002298 c := s.expr(cond)
2299 b := s.endBlock()
2300 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07002301 b.SetControl(c)
Keith Randall99187312015-11-02 16:56:53 -08002302 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2303 b.AddEdgeTo(yes)
2304 b.AddEdgeTo(no)
2305}
2306
Keith Randalld4663e12016-03-21 10:22:03 -07002307type skipMask uint8
2308
2309const (
2310 skipPtr skipMask = 1 << iota
2311 skipLen
2312 skipCap
2313)
2314
Keith Randall5ba31942016-01-25 17:06:54 -08002315// assign does left = right.
2316// Right has already been evaluated to ssa, left has not.
2317// If deref is true, then we do left = *right instead (and right has already been nil-checked).
2318// If deref is true and right == nil, just do left = 0.
2319// Include a write barrier if wb is true.
Keith Randalld4663e12016-03-21 10:22:03 -07002320// skip indicates assignments (at the top level) that can be avoided.
2321func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002322 if left.Op == ONAME && isblank(left) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002323 return
2324 }
Keith Randalld4cc51d2015-08-14 21:47:20 -07002325 t := left.Type
2326 dowidth(t)
Keith Randall6a8a9da2016-02-27 17:49:31 -08002327 if s.canSSA(left) {
Keith Randall5ba31942016-01-25 17:06:54 -08002328 if deref {
2329 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2330 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002331 if left.Op == ODOT {
2332 // We're assigning to a field of an ssa-able value.
2333 // We need to build a new structure with the new value for the
2334 // field we're assigning and the old values for the other fields.
2335 // For instance:
2336 // type T struct {a, b, c int}
2337 // var T x
2338 // x.b = 5
2339 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2340
2341 // Grab information about the structure type.
2342 t := left.Left.Type
2343 nf := t.NumFields()
2344 idx := fieldIdx(left)
2345
2346 // Grab old value of structure.
2347 old := s.expr(left.Left)
2348
2349 // Make new structure.
2350 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2351
2352 // Add fields as args.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002353 for i := 0; i < nf; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002354 if i == idx {
2355 new.AddArg(right)
2356 } else {
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002357 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
Keith Randalla734bbc2016-01-11 21:05:33 -08002358 }
2359 }
2360
2361 // Recursively assign the new value we've made to the base of the dot op.
Keith Randalld4663e12016-03-21 10:22:03 -07002362 s.assign(left.Left, new, false, false, line, 0)
Keith Randalla734bbc2016-01-11 21:05:33 -08002363 // TODO: do we need to update named values here?
2364 return
2365 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002366 // Update variable assignment.
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002367 s.vars[left] = right
Keith Randallc24681a2015-10-22 14:22:38 -07002368 s.addNamedValue(left, right)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002369 return
2370 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002371 // Left is not ssa-able. Compute its address.
David Chase57670ad2015-10-09 16:48:30 -04002372 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002373 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002374 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002375 }
Keith Randall5ba31942016-01-25 17:06:54 -08002376 if deref {
2377 // Treat as a mem->mem move.
2378 if right == nil {
2379 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2380 return
2381 }
2382 if wb {
2383 s.insertWBmove(t, addr, right, line)
2384 return
2385 }
2386 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2387 return
Keith Randalle3869a62015-09-07 23:18:02 -07002388 }
Keith Randall5ba31942016-01-25 17:06:54 -08002389 // Treat as a store.
2390 if wb {
Keith Randalld4663e12016-03-21 10:22:03 -07002391 if skip&skipPtr != 0 {
2392 // Special case: if we don't write back the pointers, don't bother
2393 // doing the write barrier check.
2394 s.storeTypeScalars(t, addr, right, skip)
2395 return
2396 }
2397 s.insertWBstore(t, addr, right, line, skip)
2398 return
2399 }
2400 if skip != 0 {
2401 if skip&skipPtr == 0 {
2402 s.storeTypePtrs(t, addr, right)
2403 }
2404 s.storeTypeScalars(t, addr, right, skip)
Keith Randall5ba31942016-01-25 17:06:54 -08002405 return
2406 }
2407 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002408}
2409
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002410// zeroVal returns the zero value for type t.
2411func (s *state) zeroVal(t *Type) *ssa.Value {
2412 switch {
Keith Randall9cb332e2015-07-28 14:19:20 -07002413 case t.IsInteger():
2414 switch t.Size() {
2415 case 1:
2416 return s.constInt8(t, 0)
2417 case 2:
2418 return s.constInt16(t, 0)
2419 case 4:
2420 return s.constInt32(t, 0)
2421 case 8:
2422 return s.constInt64(t, 0)
2423 default:
2424 s.Fatalf("bad sized integer type %s", t)
2425 }
Todd Neal752fe4d2015-08-25 19:21:45 -05002426 case t.IsFloat():
2427 switch t.Size() {
2428 case 4:
2429 return s.constFloat32(t, 0)
2430 case 8:
2431 return s.constFloat64(t, 0)
2432 default:
2433 s.Fatalf("bad sized float type %s", t)
2434 }
David Chase52578582015-08-28 14:24:10 -04002435 case t.IsComplex():
2436 switch t.Size() {
2437 case 8:
2438 z := s.constFloat32(Types[TFLOAT32], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002439 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002440 case 16:
2441 z := s.constFloat64(Types[TFLOAT64], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002442 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002443 default:
2444 s.Fatalf("bad sized complex type %s", t)
2445 }
2446
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002447 case t.IsString():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002448 return s.constEmptyString(t)
Matthew Dempsky788f1122016-03-28 10:55:44 -07002449 case t.IsPtrShaped():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002450 return s.constNil(t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002451 case t.IsBoolean():
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07002452 return s.constBool(false)
Keith Randall9f954db2015-08-18 10:26:28 -07002453 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002454 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07002455 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002456 return s.constSlice(t)
Keith Randalla734bbc2016-01-11 21:05:33 -08002457 case t.IsStruct():
2458 n := t.NumFields()
2459 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002460 for i := 0; i < n; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002461 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2462 }
2463 return v
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002464 }
2465 s.Unimplementedf("zero for type %v not implemented", t)
2466 return nil
2467}
2468
Keith Randalld24768e2015-09-09 23:56:59 -07002469type callKind int8
2470
2471const (
2472 callNormal callKind = iota
2473 callDefer
2474 callGo
2475)
2476
David Chase8eec2bb2016-03-11 00:10:52 -05002477// isSSAIntrinsic1 returns true if n is a call to a recognized 1-arg intrinsic
2478// that can be handled by the SSA backend.
2479// SSA uses this, but so does the front end to see if should not
2480// inline a function because it is a candidate for intrinsic
2481// substitution.
2482func isSSAIntrinsic1(s *Sym) bool {
2483 // The test below is not quite accurate -- in the event that
2484 // a function is disabled on a per-function basis, for example
2485 // because of hash-keyed binary failure search, SSA might be
2486 // disabled for that function but it would not be noted here,
2487 // and thus an inlining would not occur (in practice, inlining
2488 // so far has only been noticed for Bswap32 and the 16-bit count
2489 // leading/trailing instructions, but heuristics might change
2490 // in the future or on different architectures).
Matthew Dempskyc6e11fe2016-04-06 12:01:40 -07002491 if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.LinkArch.Family != sys.AMD64 {
David Chase8eec2bb2016-03-11 00:10:52 -05002492 return false
2493 }
2494 if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
2495 switch s.Name {
2496 case
2497 "Ctz64", "Ctz32", "Ctz16",
2498 "Bswap64", "Bswap32":
2499 return true
2500 }
2501 }
2502 return false
2503}
2504
2505func isIntrinsicCall1(n *Node) bool {
2506 if n == nil || n.Left == nil {
2507 return false
2508 }
2509 return isSSAIntrinsic1(n.Left.Sym)
2510}
2511
2512// intrinsicFirstArg extracts arg from n.List and eval
2513func (s *state) intrinsicFirstArg(n *Node) *ssa.Value {
2514 x := n.List.First()
2515 if x.Op == OAS {
2516 x = x.Right
2517 }
2518 return s.expr(x)
2519}
2520
2521// intrinsicCall1 converts a call to a recognized 1-arg intrinsic
2522// into the intrinsic
2523func (s *state) intrinsicCall1(n *Node) *ssa.Value {
2524 var result *ssa.Value
2525 switch n.Left.Sym.Name {
2526 case "Ctz64":
2527 result = s.newValue1(ssa.OpCtz64, Types[TUINT64], s.intrinsicFirstArg(n))
2528 case "Ctz32":
2529 result = s.newValue1(ssa.OpCtz32, Types[TUINT32], s.intrinsicFirstArg(n))
2530 case "Ctz16":
2531 result = s.newValue1(ssa.OpCtz16, Types[TUINT16], s.intrinsicFirstArg(n))
2532 case "Bswap64":
2533 result = s.newValue1(ssa.OpBswap64, Types[TUINT64], s.intrinsicFirstArg(n))
2534 case "Bswap32":
2535 result = s.newValue1(ssa.OpBswap32, Types[TUINT32], s.intrinsicFirstArg(n))
2536 }
2537 if result == nil {
2538 Fatalf("Unknown special call: %v", n.Left.Sym)
2539 }
2540 if ssa.IntrinsicsDebug > 0 {
2541 Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, result.LongString())
2542 }
2543 return result
2544}
2545
Keith Randall5ba31942016-01-25 17:06:54 -08002546// Calls the function n using the specified call type.
2547// Returns the address of the return value (or nil if none).
Keith Randalld24768e2015-09-09 23:56:59 -07002548func (s *state) call(n *Node, k callKind) *ssa.Value {
2549 var sym *Sym // target symbol (if static)
2550 var closure *ssa.Value // ptr to closure to run (if dynamic)
2551 var codeptr *ssa.Value // ptr to target code (if dynamic)
2552 var rcvr *ssa.Value // receiver to set
2553 fn := n.Left
2554 switch n.Op {
2555 case OCALLFUNC:
2556 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2557 sym = fn.Sym
2558 break
2559 }
2560 closure = s.expr(fn)
Keith Randalld24768e2015-09-09 23:56:59 -07002561 case OCALLMETH:
2562 if fn.Op != ODOTMETH {
2563 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2564 }
Keith Randalld24768e2015-09-09 23:56:59 -07002565 if k == callNormal {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002566 sym = fn.Sym
Keith Randalld24768e2015-09-09 23:56:59 -07002567 break
2568 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002569 n2 := newname(fn.Sym)
Keith Randalld24768e2015-09-09 23:56:59 -07002570 n2.Class = PFUNC
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002571 n2.Lineno = fn.Lineno
2572 closure = s.expr(n2)
Keith Randalld24768e2015-09-09 23:56:59 -07002573 // Note: receiver is already assigned in n.List, so we don't
2574 // want to set it here.
2575 case OCALLINTER:
2576 if fn.Op != ODOTINTER {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002577 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(fn.Op, 0))
Keith Randalld24768e2015-09-09 23:56:59 -07002578 }
2579 i := s.expr(fn.Left)
2580 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2581 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2582 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2583 if k == callNormal {
2584 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2585 } else {
2586 closure = itab
2587 }
2588 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2589 }
2590 dowidth(fn.Type)
Josh Bleecher Snyder361b3342016-03-28 14:31:57 -07002591 stksize := fn.Type.ArgWidth() // includes receiver
Keith Randalld24768e2015-09-09 23:56:59 -07002592
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002593 // Run all argument assignments. The arg slots have already
Keith Randalld24768e2015-09-09 23:56:59 -07002594 // been offset by the appropriate amount (+2*widthptr for go/defer,
2595 // +widthptr for interface calls).
2596 // For OCALLMETH, the receiver is set in these statements.
2597 s.stmtList(n.List)
2598
2599 // Set receiver (for interface calls)
2600 if rcvr != nil {
Keith Randall7c4fbb62015-10-19 13:56:55 -07002601 argStart := Ctxt.FixedFrameSize()
Keith Randalld24768e2015-09-09 23:56:59 -07002602 if k != callNormal {
2603 argStart += int64(2 * Widthptr)
2604 }
2605 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002606 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002607 }
2608
2609 // Defer/go args
2610 if k != callNormal {
2611 // Write argsize and closure (args to Newproc/Deferproc).
2612 argsize := s.constInt32(Types[TUINT32], int32(stksize))
Keith Randallb32217a2015-09-17 16:45:10 -07002613 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002614 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002615 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002616 stksize += 2 * int64(Widthptr)
2617 }
2618
2619 // call target
2620 bNext := s.f.NewBlock(ssa.BlockPlain)
2621 var call *ssa.Value
2622 switch {
2623 case k == callDefer:
2624 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2625 case k == callGo:
2626 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2627 case closure != nil:
2628 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2629 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2630 case codeptr != nil:
2631 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2632 case sym != nil:
2633 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2634 default:
Josh Bleecher Snyderf0272412016-04-22 07:14:10 -07002635 Fatalf("bad call type %s %v", n.Op, n)
Keith Randalld24768e2015-09-09 23:56:59 -07002636 }
2637 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2638
2639 // Finish call block
Keith Randallb32217a2015-09-17 16:45:10 -07002640 s.vars[&memVar] = call
Keith Randalld24768e2015-09-09 23:56:59 -07002641 b := s.endBlock()
2642 b.Kind = ssa.BlockCall
Keith Randall56e0ecc2016-03-15 20:45:50 -07002643 b.SetControl(call)
Keith Randalld24768e2015-09-09 23:56:59 -07002644 b.AddEdgeTo(bNext)
Keith Randallddc6b642016-03-09 19:27:57 -08002645 if k == callDefer {
2646 // Add recover edge to exit code.
2647 b.Kind = ssa.BlockDefer
2648 r := s.f.NewBlock(ssa.BlockPlain)
2649 s.startBlock(r)
2650 s.exit()
2651 b.AddEdgeTo(r)
2652 b.Likely = ssa.BranchLikely
2653 }
Keith Randalld24768e2015-09-09 23:56:59 -07002654
Keith Randall5ba31942016-01-25 17:06:54 -08002655 // Start exit block, find address of result.
Keith Randalld24768e2015-09-09 23:56:59 -07002656 s.startBlock(bNext)
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002657 res := n.Left.Type.Results()
2658 if res.NumFields() == 0 || k != callNormal {
Keith Randalld24768e2015-09-09 23:56:59 -07002659 // call has no return value. Continue with the next statement.
2660 return nil
2661 }
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002662 fp := res.Field(0)
Cherry Zhang508a4242016-04-18 10:30:20 -04002663 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset+Ctxt.FixedFrameSize(), s.sp)
Keith Randalld24768e2015-09-09 23:56:59 -07002664}
2665
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002666// etypesign returns the signed-ness of e, for integer/pointer etypes.
2667// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
Keith Randall4304fbc2015-11-16 13:20:16 -08002668func etypesign(e EType) int8 {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002669 switch e {
2670 case TINT8, TINT16, TINT32, TINT64, TINT:
2671 return -1
2672 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2673 return +1
2674 }
2675 return 0
2676}
2677
Todd Neald076ef72015-10-15 20:25:32 -05002678// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2679// This improves the effectiveness of cse by using the same Aux values for the
2680// same symbols.
2681func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2682 switch sym.(type) {
2683 default:
2684 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2685 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2686 // these are the only valid types
2687 }
2688
2689 if lsym, ok := s.varsyms[n]; ok {
2690 return lsym
2691 } else {
2692 s.varsyms[n] = sym
2693 return sym
2694 }
2695}
2696
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07002697// 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 -07002698// The value that the returned Value represents is guaranteed to be non-nil.
David Chase57670ad2015-10-09 16:48:30 -04002699// If bounded is true then this address does not require a nil check for its operand
2700// even if that would otherwise be implied.
2701func (s *state) addr(n *Node, bounded bool) *ssa.Value {
Keith Randallc24681a2015-10-22 14:22:38 -07002702 t := Ptrto(n.Type)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002703 switch n.Op {
2704 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07002705 switch n.Class {
2706 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -07002707 // global variable
Todd Neal74180dd2015-10-27 21:35:48 -05002708 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
Keith Randallc24681a2015-10-22 14:22:38 -07002709 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
Josh Bleecher Snyder67df7932015-07-28 11:08:44 -07002710 // TODO: Make OpAddr use AuxInt as well as Aux.
2711 if n.Xoffset != 0 {
2712 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2713 }
2714 return v
David Chase956f3192015-09-11 16:40:05 -04002715 case PPARAM:
2716 // parameter slot
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002717 v := s.decladdrs[n]
Keith Randall4304fbc2015-11-16 13:20:16 -08002718 if v != nil {
2719 return v
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002720 }
Keith Randall4304fbc2015-11-16 13:20:16 -08002721 if n.String() == ".fp" {
2722 // Special arg that points to the frame pointer.
2723 // (Used by the race detector, others?)
2724 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2725 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2726 }
2727 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2728 return nil
Keith Randalld2107fc2015-08-24 02:16:19 -07002729 case PAUTO:
Todd Neal40bfec02016-03-11 20:03:17 -06002730 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002731 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002732 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
Todd Neald076ef72015-10-15 20:25:32 -05002733 // ensure that we reuse symbols for out parameters so
2734 // that cse works on their addresses
2735 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002736 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002737 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002738 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -07002739 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002740 s.Unimplementedf("variable address class %v not implemented", n.Class)
Keith Randall290d8fc2015-06-10 15:03:06 -07002741 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07002742 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002743 case OINDREG:
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002744 // indirect off a register
Keith Randallcfc2aa52015-05-18 16:44:20 -07002745 // used for storing/loading arguments/returns to/from callees
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002746 if int(n.Reg) != Thearch.REGSP {
2747 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2748 return nil
2749 }
Keith Randallc24681a2015-10-22 14:22:38 -07002750 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002751 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002752 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002753 a := s.expr(n.Left)
2754 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002755 i = s.extendIndex(i)
Keith Randallc24681a2015-10-22 14:22:38 -07002756 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
Keith Randall46e62f82015-08-18 14:17:30 -07002757 if !n.Bounded {
2758 s.boundsCheck(i, len)
2759 }
Keith Randallc24681a2015-10-22 14:22:38 -07002760 p := s.newValue1(ssa.OpSlicePtr, t, a)
2761 return s.newValue2(ssa.OpPtrIndex, t, p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002762 } else { // array
David Chase57670ad2015-10-09 16:48:30 -04002763 a := s.addr(n.Left, bounded)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002764 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002765 i = s.extendIndex(i)
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07002766 len := s.constInt(Types[TINT], n.Left.Type.NumElem())
Keith Randall46e62f82015-08-18 14:17:30 -07002767 if !n.Bounded {
2768 s.boundsCheck(i, len)
2769 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002770 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002771 }
Todd Nealb383de22015-07-13 21:22:16 -05002772 case OIND:
Keith Randall3c1a4c12016-04-19 21:06:53 -07002773 return s.exprPtr(n.Left, bounded, n.Lineno)
Keith Randallc3c84a22015-07-13 15:55:37 -07002774 case ODOT:
David Chase57670ad2015-10-09 16:48:30 -04002775 p := s.addr(n.Left, bounded)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002776 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
Keith Randallc3c84a22015-07-13 15:55:37 -07002777 case ODOTPTR:
Keith Randall3c1a4c12016-04-19 21:06:53 -07002778 p := s.exprPtr(n.Left, bounded, n.Lineno)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002779 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
David Chase956f3192015-09-11 16:40:05 -04002780 case OCLOSUREVAR:
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002781 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
2782 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
David Chase32ffbf72015-10-08 17:14:12 -04002783 case OPARAM:
2784 p := n.Left
2785 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2786 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2787 }
2788
2789 // Recover original offset to address passed-in param value.
2790 original_p := *p
2791 original_p.Xoffset = n.Xoffset
2792 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
Keith Randallc24681a2015-10-22 14:22:38 -07002793 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase57670ad2015-10-09 16:48:30 -04002794 case OCONVNOP:
2795 addr := s.addr(n.Left, bounded)
Keith Randallc24681a2015-10-22 14:22:38 -07002796 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
Keith Randall5ba31942016-01-25 17:06:54 -08002797 case OCALLFUNC, OCALLINTER, OCALLMETH:
2798 return s.call(n, callNormal)
David Chase57670ad2015-10-09 16:48:30 -04002799
Keith Randallcfc2aa52015-05-18 16:44:20 -07002800 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002801 s.Unimplementedf("unhandled addr %v", Oconv(n.Op, 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -07002802 return nil
2803 }
2804}
2805
Keith Randall290d8fc2015-06-10 15:03:06 -07002806// canSSA reports whether n is SSA-able.
Keith Randalla734bbc2016-01-11 21:05:33 -08002807// n must be an ONAME (or an ODOT sequence with an ONAME base).
Keith Randall6a8a9da2016-02-27 17:49:31 -08002808func (s *state) canSSA(n *Node) bool {
Keith Randalla734bbc2016-01-11 21:05:33 -08002809 for n.Op == ODOT {
2810 n = n.Left
2811 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002812 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +01002813 return false
Keith Randall290d8fc2015-06-10 15:03:06 -07002814 }
2815 if n.Addrtaken {
2816 return false
2817 }
2818 if n.Class&PHEAP != 0 {
2819 return false
2820 }
Josh Bleecher Snyder96548732015-08-28 13:35:32 -07002821 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -08002822 case PEXTERN, PPARAMREF:
2823 // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
Keith Randall290d8fc2015-06-10 15:03:06 -07002824 return false
Keith Randall6a8a9da2016-02-27 17:49:31 -08002825 case PPARAMOUT:
2826 if hasdefer {
2827 // TODO: handle this case? Named return values must be
2828 // in memory so that the deferred function can see them.
2829 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
2830 return false
2831 }
2832 if s.cgoUnsafeArgs {
2833 // Cgo effectively takes the address of all result args,
2834 // but the compiler can't see that.
2835 return false
2836 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002837 }
Keith Randall8a1f6212015-09-08 21:28:44 -07002838 if n.Class == PPARAM && n.String() == ".this" {
2839 // wrappers generated by genwrapper need to update
2840 // the .this pointer in place.
Keith Randall6a8a9da2016-02-27 17:49:31 -08002841 // TODO: treat as a PPARMOUT?
Keith Randall8a1f6212015-09-08 21:28:44 -07002842 return false
2843 }
Keith Randall9f954db2015-08-18 10:26:28 -07002844 return canSSAType(n.Type)
2845 // TODO: try to make more variables SSAable?
2846}
2847
2848// canSSA reports whether variables of type t are SSA-able.
2849func canSSAType(t *Type) bool {
2850 dowidth(t)
2851 if t.Width > int64(4*Widthptr) {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002852 // 4*Widthptr is an arbitrary constant. We want it
Keith Randall9f954db2015-08-18 10:26:28 -07002853 // to be at least 3*Widthptr so slices can be registerized.
2854 // Too big and we'll introduce too much register pressure.
Daniel Morsing66b47812015-06-27 15:45:20 +01002855 return false
2856 }
Keith Randall9f954db2015-08-18 10:26:28 -07002857 switch t.Etype {
2858 case TARRAY:
Keith Randall9f954db2015-08-18 10:26:28 -07002859 // We can't do arrays because dynamic indexing is
2860 // not supported on SSA variables.
2861 // TODO: maybe allow if length is <=1? All indexes
2862 // are constant? Might be good for the arrays
2863 // introduced by the compiler for variadic functions.
2864 return false
2865 case TSTRUCT:
Matthew Dempskydbed1c62016-03-17 13:26:08 -07002866 if t.NumFields() > ssa.MaxStruct {
Keith Randall9f954db2015-08-18 10:26:28 -07002867 return false
2868 }
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002869 for _, t1 := range t.Fields().Slice() {
Keith Randall9f954db2015-08-18 10:26:28 -07002870 if !canSSAType(t1.Type) {
2871 return false
2872 }
2873 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002874 return true
Keith Randall9f954db2015-08-18 10:26:28 -07002875 default:
2876 return true
2877 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002878}
2879
Keith Randall3c1a4c12016-04-19 21:06:53 -07002880// exprPtr evaluates n to a pointer and nil-checks it.
2881func (s *state) exprPtr(n *Node, bounded bool, lineno int32) *ssa.Value {
2882 p := s.expr(n)
2883 if bounded || n.NonNil {
2884 if s.f.Config.Debug_checknil() && lineno > 1 {
2885 s.f.Config.Warnl(lineno, "removed nil check")
2886 }
2887 return p
2888 }
2889 s.nilCheck(p)
2890 return p
2891}
2892
Keith Randallcfc2aa52015-05-18 16:44:20 -07002893// nilCheck generates nil pointer checking code.
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002894// Starts a new block on return, unless nil checks are disabled.
Josh Bleecher Snyder7e74e432015-07-24 11:55:52 -07002895// Used only for automatically inserted nil checks,
2896// not for user code like 'x != nil'.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002897func (s *state) nilCheck(ptr *ssa.Value) {
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002898 if Disable_checknil != 0 {
2899 return
2900 }
Keith Randall31115a52015-10-23 19:12:49 -07002901 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07002902 b := s.endBlock()
Keith Randall31115a52015-10-23 19:12:49 -07002903 b.Kind = ssa.BlockCheck
Keith Randall56e0ecc2016-03-15 20:45:50 -07002904 b.SetControl(chk)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002905 bNext := s.f.NewBlock(ssa.BlockPlain)
Todd Neal47d67992015-08-28 21:36:29 -05002906 b.AddEdgeTo(bNext)
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002907 s.startBlock(bNext)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002908}
2909
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002910// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002911// Starts a new block on return.
2912func (s *state) boundsCheck(idx, len *ssa.Value) {
Keith Randall8d236812015-08-18 15:25:40 -07002913 if Debug['B'] != 0 {
2914 return
2915 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002916 // TODO: convert index to full width?
2917 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2918
2919 // bounds check
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002920 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002921 s.check(cmp, Panicindex)
Keith Randall3526cf52015-08-24 23:52:03 -07002922}
2923
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002924// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
Keith Randall3526cf52015-08-24 23:52:03 -07002925// Starts a new block on return.
2926func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2927 if Debug['B'] != 0 {
2928 return
2929 }
2930 // TODO: convert index to full width?
2931 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2932
2933 // bounds check
2934 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002935 s.check(cmp, panicslice)
Keith Randall3526cf52015-08-24 23:52:03 -07002936}
2937
Keith Randall3a70bf92015-09-17 16:54:15 -07002938// If cmp (a bool) is true, panic using the given function.
2939func (s *state) check(cmp *ssa.Value, fn *Node) {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002940 b := s.endBlock()
2941 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07002942 b.SetControl(cmp)
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07002943 b.Likely = ssa.BranchLikely
Keith Randallcfc2aa52015-05-18 16:44:20 -07002944 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall74e568f2015-11-09 21:35:40 -08002945 line := s.peekLine()
2946 bPanic := s.panics[funcLine{fn, line}]
2947 if bPanic == nil {
2948 bPanic = s.f.NewBlock(ssa.BlockPlain)
2949 s.panics[funcLine{fn, line}] = bPanic
2950 s.startBlock(bPanic)
2951 // The panic call takes/returns memory to ensure that the right
2952 // memory state is observed if the panic happens.
2953 s.rtcall(fn, false, nil)
2954 }
Todd Neal47d67992015-08-28 21:36:29 -05002955 b.AddEdgeTo(bNext)
2956 b.AddEdgeTo(bPanic)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002957 s.startBlock(bNext)
2958}
2959
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002960// rtcall issues a call to the given runtime function fn with the listed args.
2961// Returns a slice of results of the given result types.
2962// The call is added to the end of the current block.
2963// If returns is false, the block is marked as an exit block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002964// If returns is true, the block is marked as a call block. A new block
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002965// is started to load the return values.
2966func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2967 // Write args to the stack
2968 var off int64 // TODO: arch-dependent starting offset?
2969 for _, arg := range args {
2970 t := arg.Type
2971 off = Rnd(off, t.Alignment())
2972 ptr := s.sp
2973 if off != 0 {
2974 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2975 }
2976 size := t.Size()
2977 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2978 off += size
2979 }
2980 off = Rnd(off, int64(Widthptr))
2981
2982 // Issue call
2983 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2984 s.vars[&memVar] = call
2985
2986 // Finish block
2987 b := s.endBlock()
2988 if !returns {
2989 b.Kind = ssa.BlockExit
Keith Randall56e0ecc2016-03-15 20:45:50 -07002990 b.SetControl(call)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002991 call.AuxInt = off
2992 if len(results) > 0 {
2993 Fatalf("panic call can't have results")
2994 }
2995 return nil
2996 }
2997 b.Kind = ssa.BlockCall
Keith Randall56e0ecc2016-03-15 20:45:50 -07002998 b.SetControl(call)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002999 bNext := s.f.NewBlock(ssa.BlockPlain)
3000 b.AddEdgeTo(bNext)
3001 s.startBlock(bNext)
3002
3003 // Load results
3004 res := make([]*ssa.Value, len(results))
3005 for i, t := range results {
3006 off = Rnd(off, t.Alignment())
3007 ptr := s.sp
3008 if off != 0 {
3009 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
3010 }
3011 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
3012 off += t.Size()
3013 }
3014 off = Rnd(off, int64(Widthptr))
3015
3016 // Remember how much callee stack space we needed.
3017 call.AuxInt = off
3018
3019 return res
3020}
3021
Keith Randall5ba31942016-01-25 17:06:54 -08003022// insertWBmove inserts the assignment *left = *right including a write barrier.
3023// t is the type being assigned.
3024func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
Keith Randall4304fbc2015-11-16 13:20:16 -08003025 // if writeBarrier.enabled {
Keith Randall5ba31942016-01-25 17:06:54 -08003026 // typedmemmove(&t, left, right)
3027 // } else {
3028 // *left = *right
Keith Randall9d22c102015-09-11 11:02:57 -07003029 // }
Keith Randall15ed37d2016-03-16 21:51:17 -07003030
3031 if s.noWB {
3032 s.Fatalf("write barrier prohibited")
3033 }
3034 if s.WBLineno == 0 {
3035 s.WBLineno = left.Line
3036 }
Keith Randall9d22c102015-09-11 11:02:57 -07003037 bThen := s.f.NewBlock(ssa.BlockPlain)
Keith Randall5ba31942016-01-25 17:06:54 -08003038 bElse := s.f.NewBlock(ssa.BlockPlain)
3039 bEnd := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07003040
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003041 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05003042 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003043 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05003044 // Load word, test byte, avoiding partial register write from load byte.
3045 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
3046 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall9d22c102015-09-11 11:02:57 -07003047 b := s.endBlock()
3048 b.Kind = ssa.BlockIf
3049 b.Likely = ssa.BranchUnlikely
Keith Randall56e0ecc2016-03-15 20:45:50 -07003050 b.SetControl(flag)
Keith Randall9d22c102015-09-11 11:02:57 -07003051 b.AddEdgeTo(bThen)
Keith Randall5ba31942016-01-25 17:06:54 -08003052 b.AddEdgeTo(bElse)
Keith Randall9d22c102015-09-11 11:02:57 -07003053
3054 s.startBlock(bThen)
Keith Randall9d22c102015-09-11 11:02:57 -07003055 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
Keith Randall5ba31942016-01-25 17:06:54 -08003056 s.rtcall(typedmemmove, true, nil, taddr, left, right)
3057 s.endBlock().AddEdgeTo(bEnd)
3058
3059 s.startBlock(bElse)
3060 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
3061 s.endBlock().AddEdgeTo(bEnd)
3062
3063 s.startBlock(bEnd)
Keith Randall9d22c102015-09-11 11:02:57 -07003064
David Chase729abfa2015-10-26 17:34:06 -04003065 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003066 Warnl(line, "write barrier")
David Chase729abfa2015-10-26 17:34:06 -04003067 }
Keith Randall5ba31942016-01-25 17:06:54 -08003068}
David Chase729abfa2015-10-26 17:34:06 -04003069
Keith Randall5ba31942016-01-25 17:06:54 -08003070// insertWBstore inserts the assignment *left = right including a write barrier.
3071// t is the type being assigned.
Keith Randalld4663e12016-03-21 10:22:03 -07003072func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) {
Keith Randall5ba31942016-01-25 17:06:54 -08003073 // store scalar fields
3074 // if writeBarrier.enabled {
3075 // writebarrierptr for pointer fields
3076 // } else {
3077 // store pointer fields
3078 // }
3079
Keith Randall15ed37d2016-03-16 21:51:17 -07003080 if s.noWB {
3081 s.Fatalf("write barrier prohibited")
3082 }
3083 if s.WBLineno == 0 {
3084 s.WBLineno = left.Line
3085 }
Keith Randalld4663e12016-03-21 10:22:03 -07003086 s.storeTypeScalars(t, left, right, skip)
Keith Randall5ba31942016-01-25 17:06:54 -08003087
3088 bThen := s.f.NewBlock(ssa.BlockPlain)
3089 bElse := s.f.NewBlock(ssa.BlockPlain)
3090 bEnd := s.f.NewBlock(ssa.BlockPlain)
3091
Matthew Dempskydafbcf62016-03-04 15:19:06 -08003092 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05003093 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003094 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05003095 // Load word, test byte, avoiding partial register write from load byte.
3096 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
3097 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall5ba31942016-01-25 17:06:54 -08003098 b := s.endBlock()
3099 b.Kind = ssa.BlockIf
3100 b.Likely = ssa.BranchUnlikely
Keith Randall56e0ecc2016-03-15 20:45:50 -07003101 b.SetControl(flag)
Keith Randall5ba31942016-01-25 17:06:54 -08003102 b.AddEdgeTo(bThen)
3103 b.AddEdgeTo(bElse)
3104
3105 // Issue write barriers for pointer writes.
3106 s.startBlock(bThen)
Keith Randallaebf6612016-01-29 21:57:57 -08003107 s.storeTypePtrsWB(t, left, right)
3108 s.endBlock().AddEdgeTo(bEnd)
3109
3110 // Issue regular stores for pointer writes.
3111 s.startBlock(bElse)
3112 s.storeTypePtrs(t, left, right)
3113 s.endBlock().AddEdgeTo(bEnd)
3114
3115 s.startBlock(bEnd)
3116
3117 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003118 Warnl(line, "write barrier")
Keith Randallaebf6612016-01-29 21:57:57 -08003119 }
3120}
3121
3122// do *left = right for all scalar (non-pointer) parts of t.
Keith Randalld4663e12016-03-21 10:22:03 -07003123func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask) {
Keith Randallaebf6612016-01-29 21:57:57 -08003124 switch {
3125 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
3126 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
Matthew Dempsky788f1122016-03-28 10:55:44 -07003127 case t.IsPtrShaped():
Keith Randallaebf6612016-01-29 21:57:57 -08003128 // no scalar fields.
3129 case t.IsString():
Keith Randalld4663e12016-03-21 10:22:03 -07003130 if skip&skipLen != 0 {
3131 return
3132 }
Keith Randallaebf6612016-01-29 21:57:57 -08003133 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
3134 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3135 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3136 case t.IsSlice():
Keith Randalld4663e12016-03-21 10:22:03 -07003137 if skip&skipLen == 0 {
3138 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
3139 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3140 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3141 }
3142 if skip&skipCap == 0 {
3143 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
3144 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
3145 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
3146 }
Keith Randallaebf6612016-01-29 21:57:57 -08003147 case t.IsInterface():
3148 // itab field doesn't need a write barrier (even though it is a pointer).
3149 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
3150 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
3151 case t.IsStruct():
3152 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003153 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003154 ft := t.FieldType(i)
3155 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003156 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randalld4663e12016-03-21 10:22:03 -07003157 s.storeTypeScalars(ft.(*Type), addr, val, 0)
Keith Randallaebf6612016-01-29 21:57:57 -08003158 }
3159 default:
3160 s.Fatalf("bad write barrier type %s", t)
3161 }
3162}
3163
3164// do *left = right for all pointer parts of t.
3165func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
3166 switch {
Matthew Dempsky788f1122016-03-28 10:55:44 -07003167 case t.IsPtrShaped():
Keith Randallaebf6612016-01-29 21:57:57 -08003168 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
3169 case t.IsString():
3170 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3171 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3172 case t.IsSlice():
3173 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3174 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3175 case t.IsInterface():
3176 // itab field is treated as a scalar.
3177 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3178 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3179 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
3180 case t.IsStruct():
3181 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003182 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003183 ft := t.FieldType(i)
3184 if !haspointers(ft.(*Type)) {
3185 continue
3186 }
3187 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003188 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08003189 s.storeTypePtrs(ft.(*Type), addr, val)
3190 }
3191 default:
3192 s.Fatalf("bad write barrier type %s", t)
3193 }
3194}
3195
3196// do *left = right with a write barrier for all pointer parts of t.
3197func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
Keith Randall5ba31942016-01-25 17:06:54 -08003198 switch {
Matthew Dempsky788f1122016-03-28 10:55:44 -07003199 case t.IsPtrShaped():
Keith Randall5ba31942016-01-25 17:06:54 -08003200 s.rtcall(writebarrierptr, true, nil, left, right)
3201 case t.IsString():
3202 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3203 s.rtcall(writebarrierptr, true, nil, left, ptr)
3204 case t.IsSlice():
3205 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3206 s.rtcall(writebarrierptr, true, nil, left, ptr)
3207 case t.IsInterface():
3208 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3209 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3210 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
Keith Randallaebf6612016-01-29 21:57:57 -08003211 case t.IsStruct():
3212 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003213 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003214 ft := t.FieldType(i)
3215 if !haspointers(ft.(*Type)) {
3216 continue
3217 }
3218 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003219 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08003220 s.storeTypePtrsWB(ft.(*Type), addr, val)
3221 }
Keith Randall5ba31942016-01-25 17:06:54 -08003222 default:
3223 s.Fatalf("bad write barrier type %s", t)
3224 }
Keith Randall9d22c102015-09-11 11:02:57 -07003225}
3226
Keith Randall5505e8c2015-09-12 23:27:26 -07003227// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
3228// i,j,k may be nil, in which case they are set to their default value.
3229// t is a slice, ptr to array, or string type.
3230func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
3231 var elemtype *Type
3232 var ptrtype *Type
3233 var ptr *ssa.Value
3234 var len *ssa.Value
3235 var cap *ssa.Value
3236 zero := s.constInt(Types[TINT], 0)
3237 switch {
3238 case t.IsSlice():
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003239 elemtype = t.Elem()
Keith Randall5505e8c2015-09-12 23:27:26 -07003240 ptrtype = Ptrto(elemtype)
3241 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
3242 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
3243 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
3244 case t.IsString():
3245 elemtype = Types[TUINT8]
3246 ptrtype = Ptrto(elemtype)
3247 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
3248 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
3249 cap = len
3250 case t.IsPtr():
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003251 if !t.Elem().IsArray() {
Keith Randall5505e8c2015-09-12 23:27:26 -07003252 s.Fatalf("bad ptr to array in slice %v\n", t)
3253 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003254 elemtype = t.Elem().Elem()
Keith Randall5505e8c2015-09-12 23:27:26 -07003255 ptrtype = Ptrto(elemtype)
3256 s.nilCheck(v)
3257 ptr = v
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003258 len = s.constInt(Types[TINT], t.Elem().NumElem())
Keith Randall5505e8c2015-09-12 23:27:26 -07003259 cap = len
3260 default:
3261 s.Fatalf("bad type in slice %v\n", t)
3262 }
3263
3264 // Set default values
3265 if i == nil {
3266 i = zero
3267 }
3268 if j == nil {
3269 j = len
3270 }
3271 if k == nil {
3272 k = cap
3273 }
3274
3275 // Panic if slice indices are not in bounds.
3276 s.sliceBoundsCheck(i, j)
3277 if j != k {
3278 s.sliceBoundsCheck(j, k)
3279 }
3280 if k != cap {
3281 s.sliceBoundsCheck(k, cap)
3282 }
3283
3284 // Generate the following code assuming that indexes are in bounds.
3285 // The conditional is to make sure that we don't generate a slice
3286 // that points to the next object in memory.
Keith Randall69a7c1522016-03-21 15:24:08 -07003287 // rlen = j-i
3288 // rcap = k-i
3289 // delta = i*elemsize
3290 // if rcap == 0 {
3291 // delta = 0
Keith Randall5505e8c2015-09-12 23:27:26 -07003292 // }
Keith Randall69a7c1522016-03-21 15:24:08 -07003293 // rptr = p+delta
3294 // result = (SliceMake rptr rlen rcap)
Keith Randall582baae2015-11-02 21:28:13 -08003295 subOp := s.ssaOp(OSUB, Types[TINT])
Keith Randall69a7c1522016-03-21 15:24:08 -07003296 eqOp := s.ssaOp(OEQ, Types[TINT])
Keith Randall582baae2015-11-02 21:28:13 -08003297 mulOp := s.ssaOp(OMUL, Types[TINT])
3298 rlen := s.newValue2(subOp, Types[TINT], j, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003299 var rcap *ssa.Value
3300 switch {
3301 case t.IsString():
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003302 // Capacity of the result is unimportant. However, we use
Keith Randall5505e8c2015-09-12 23:27:26 -07003303 // rcap to test if we've generated a zero-length slice.
3304 // Use length of strings for that.
3305 rcap = rlen
3306 case j == k:
3307 rcap = rlen
3308 default:
Keith Randall582baae2015-11-02 21:28:13 -08003309 rcap = s.newValue2(subOp, Types[TINT], k, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003310 }
3311
Keith Randall69a7c1522016-03-21 15:24:08 -07003312 // delta = # of elements to offset pointer by.
3313 s.vars[&deltaVar] = i
Keith Randall5505e8c2015-09-12 23:27:26 -07003314
Keith Randall69a7c1522016-03-21 15:24:08 -07003315 // Generate code to set delta=0 if the resulting capacity is zero.
3316 if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
3317 (i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
3318 cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
Keith Randall5505e8c2015-09-12 23:27:26 -07003319
Keith Randall69a7c1522016-03-21 15:24:08 -07003320 b := s.endBlock()
3321 b.Kind = ssa.BlockIf
3322 b.Likely = ssa.BranchUnlikely
3323 b.SetControl(cmp)
Keith Randall5505e8c2015-09-12 23:27:26 -07003324
Keith Randall69a7c1522016-03-21 15:24:08 -07003325 // Generate block which zeros the delta variable.
3326 nz := s.f.NewBlock(ssa.BlockPlain)
3327 b.AddEdgeTo(nz)
3328 s.startBlock(nz)
3329 s.vars[&deltaVar] = zero
3330 s.endBlock()
3331
3332 // All done.
3333 merge := s.f.NewBlock(ssa.BlockPlain)
3334 b.AddEdgeTo(merge)
3335 nz.AddEdgeTo(merge)
3336 s.startBlock(merge)
3337
3338 // TODO: use conditional moves somehow?
Keith Randall5505e8c2015-09-12 23:27:26 -07003339 }
Keith Randall5505e8c2015-09-12 23:27:26 -07003340
Keith Randall69a7c1522016-03-21 15:24:08 -07003341 // Compute rptr = ptr + delta * elemsize
3342 rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
3343 delete(s.vars, &deltaVar)
Keith Randall5505e8c2015-09-12 23:27:26 -07003344 return rptr, rlen, rcap
3345}
3346
David Chase42825882015-08-20 15:14:20 -04003347type u2fcvtTab struct {
3348 geq, cvt2F, and, rsh, or, add ssa.Op
3349 one func(*state, ssa.Type, int64) *ssa.Value
3350}
3351
3352var u64_f64 u2fcvtTab = u2fcvtTab{
3353 geq: ssa.OpGeq64,
3354 cvt2F: ssa.OpCvt64to64F,
3355 and: ssa.OpAnd64,
3356 rsh: ssa.OpRsh64Ux64,
3357 or: ssa.OpOr64,
3358 add: ssa.OpAdd64F,
3359 one: (*state).constInt64,
3360}
3361
3362var u64_f32 u2fcvtTab = u2fcvtTab{
3363 geq: ssa.OpGeq64,
3364 cvt2F: ssa.OpCvt64to32F,
3365 and: ssa.OpAnd64,
3366 rsh: ssa.OpRsh64Ux64,
3367 or: ssa.OpOr64,
3368 add: ssa.OpAdd32F,
3369 one: (*state).constInt64,
3370}
3371
3372// Excess generality on a machine with 64-bit integer registers.
3373// Not used on AMD64.
3374var u32_f32 u2fcvtTab = u2fcvtTab{
3375 geq: ssa.OpGeq32,
3376 cvt2F: ssa.OpCvt32to32F,
3377 and: ssa.OpAnd32,
3378 rsh: ssa.OpRsh32Ux32,
3379 or: ssa.OpOr32,
3380 add: ssa.OpAdd32F,
3381 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3382 return s.constInt32(t, int32(x))
3383 },
3384}
3385
3386func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3387 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3388}
3389
3390func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3391 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3392}
3393
3394func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3395 // if x >= 0 {
3396 // result = (floatY) x
3397 // } else {
3398 // y = uintX(x) ; y = x & 1
3399 // z = uintX(x) ; z = z >> 1
3400 // z = z >> 1
3401 // z = z | y
David Chase73151062015-08-26 14:25:40 -04003402 // result = floatY(z)
3403 // result = result + result
David Chase42825882015-08-20 15:14:20 -04003404 // }
3405 //
3406 // Code borrowed from old code generator.
3407 // What's going on: large 64-bit "unsigned" looks like
3408 // negative number to hardware's integer-to-float
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003409 // conversion. However, because the mantissa is only
David Chase42825882015-08-20 15:14:20 -04003410 // 63 bits, we don't need the LSB, so instead we do an
3411 // unsigned right shift (divide by two), convert, and
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003412 // double. However, before we do that, we need to be
David Chase42825882015-08-20 15:14:20 -04003413 // sure that we do not lose a "1" if that made the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003414 // difference in the resulting rounding. Therefore, we
3415 // preserve it, and OR (not ADD) it back in. The case
David Chase42825882015-08-20 15:14:20 -04003416 // that matters is when the eleven discarded bits are
3417 // equal to 10000000001; that rounds up, and the 1 cannot
3418 // be lost else it would round down if the LSB of the
3419 // candidate mantissa is 0.
3420 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3421 b := s.endBlock()
3422 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003423 b.SetControl(cmp)
David Chase42825882015-08-20 15:14:20 -04003424 b.Likely = ssa.BranchLikely
3425
3426 bThen := s.f.NewBlock(ssa.BlockPlain)
3427 bElse := s.f.NewBlock(ssa.BlockPlain)
3428 bAfter := s.f.NewBlock(ssa.BlockPlain)
3429
Todd Neal47d67992015-08-28 21:36:29 -05003430 b.AddEdgeTo(bThen)
David Chase42825882015-08-20 15:14:20 -04003431 s.startBlock(bThen)
3432 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3433 s.vars[n] = a0
3434 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003435 bThen.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003436
Todd Neal47d67992015-08-28 21:36:29 -05003437 b.AddEdgeTo(bElse)
David Chase42825882015-08-20 15:14:20 -04003438 s.startBlock(bElse)
3439 one := cvttab.one(s, ft, 1)
3440 y := s.newValue2(cvttab.and, ft, x, one)
3441 z := s.newValue2(cvttab.rsh, ft, x, one)
3442 z = s.newValue2(cvttab.or, ft, z, y)
3443 a := s.newValue1(cvttab.cvt2F, tt, z)
3444 a1 := s.newValue2(cvttab.add, tt, a, a)
3445 s.vars[n] = a1
3446 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003447 bElse.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003448
3449 s.startBlock(bAfter)
3450 return s.variable(n, n.Type)
3451}
3452
Todd Neal707af252015-08-28 15:56:43 -05003453// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3454func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3455 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3456 s.Fatalf("node must be a map or a channel")
3457 }
Todd Neale0e40682015-08-26 18:40:52 -05003458 // if n == nil {
3459 // return 0
3460 // } else {
Todd Neal707af252015-08-28 15:56:43 -05003461 // // len
Todd Neale0e40682015-08-26 18:40:52 -05003462 // return *((*int)n)
Todd Neal707af252015-08-28 15:56:43 -05003463 // // cap
3464 // return *(((*int)n)+1)
Todd Neale0e40682015-08-26 18:40:52 -05003465 // }
3466 lenType := n.Type
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003467 nilValue := s.constNil(Types[TUINTPTR])
Todd Neal67ac8a32015-08-28 15:20:54 -05003468 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
Todd Neale0e40682015-08-26 18:40:52 -05003469 b := s.endBlock()
3470 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003471 b.SetControl(cmp)
Todd Neale0e40682015-08-26 18:40:52 -05003472 b.Likely = ssa.BranchUnlikely
3473
3474 bThen := s.f.NewBlock(ssa.BlockPlain)
3475 bElse := s.f.NewBlock(ssa.BlockPlain)
3476 bAfter := s.f.NewBlock(ssa.BlockPlain)
3477
Todd Neal707af252015-08-28 15:56:43 -05003478 // length/capacity of a nil map/chan is zero
Todd Neal47d67992015-08-28 21:36:29 -05003479 b.AddEdgeTo(bThen)
Todd Neale0e40682015-08-26 18:40:52 -05003480 s.startBlock(bThen)
3481 s.vars[n] = s.zeroVal(lenType)
3482 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003483 bThen.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003484
Todd Neal47d67992015-08-28 21:36:29 -05003485 b.AddEdgeTo(bElse)
Todd Neale0e40682015-08-26 18:40:52 -05003486 s.startBlock(bElse)
Todd Neal707af252015-08-28 15:56:43 -05003487 if n.Op == OLEN {
3488 // length is stored in the first word for map/chan
3489 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3490 } else if n.Op == OCAP {
3491 // capacity is stored in the second word for chan
3492 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3493 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3494 } else {
3495 s.Fatalf("op must be OLEN or OCAP")
3496 }
Todd Neale0e40682015-08-26 18:40:52 -05003497 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003498 bElse.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003499
3500 s.startBlock(bAfter)
3501 return s.variable(n, lenType)
3502}
3503
David Chase73151062015-08-26 14:25:40 -04003504type f2uCvtTab struct {
3505 ltf, cvt2U, subf ssa.Op
3506 value func(*state, ssa.Type, float64) *ssa.Value
3507}
3508
3509var f32_u64 f2uCvtTab = f2uCvtTab{
3510 ltf: ssa.OpLess32F,
3511 cvt2U: ssa.OpCvt32Fto64,
3512 subf: ssa.OpSub32F,
3513 value: (*state).constFloat32,
3514}
3515
3516var f64_u64 f2uCvtTab = f2uCvtTab{
3517 ltf: ssa.OpLess64F,
3518 cvt2U: ssa.OpCvt64Fto64,
3519 subf: ssa.OpSub64F,
3520 value: (*state).constFloat64,
3521}
3522
3523func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3524 return s.floatToUint(&f32_u64, n, x, ft, tt)
3525}
3526func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3527 return s.floatToUint(&f64_u64, n, x, ft, tt)
3528}
3529
3530func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3531 // if x < 9223372036854775808.0 {
3532 // result = uintY(x)
3533 // } else {
3534 // y = x - 9223372036854775808.0
3535 // z = uintY(y)
3536 // result = z | -9223372036854775808
3537 // }
3538 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3539 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3540 b := s.endBlock()
3541 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003542 b.SetControl(cmp)
David Chase73151062015-08-26 14:25:40 -04003543 b.Likely = ssa.BranchLikely
3544
3545 bThen := s.f.NewBlock(ssa.BlockPlain)
3546 bElse := s.f.NewBlock(ssa.BlockPlain)
3547 bAfter := s.f.NewBlock(ssa.BlockPlain)
3548
Todd Neal47d67992015-08-28 21:36:29 -05003549 b.AddEdgeTo(bThen)
David Chase73151062015-08-26 14:25:40 -04003550 s.startBlock(bThen)
3551 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3552 s.vars[n] = a0
3553 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003554 bThen.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003555
Todd Neal47d67992015-08-28 21:36:29 -05003556 b.AddEdgeTo(bElse)
David Chase73151062015-08-26 14:25:40 -04003557 s.startBlock(bElse)
3558 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3559 y = s.newValue1(cvttab.cvt2U, tt, y)
3560 z := s.constInt64(tt, -9223372036854775808)
3561 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3562 s.vars[n] = a1
3563 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003564 bElse.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003565
3566 s.startBlock(bAfter)
3567 return s.variable(n, n.Type)
3568}
3569
Keith Randall269baa92015-09-17 10:31:16 -07003570// ifaceType returns the value for the word containing the type.
3571// n is the node for the interface expression.
3572// v is the corresponding value.
3573func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3574 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3575
Matthew Dempsky00e5a682016-04-01 13:36:24 -07003576 if n.Type.IsEmptyInterface() {
Keith Randall269baa92015-09-17 10:31:16 -07003577 // Have *eface. The type is the first word in the struct.
3578 return s.newValue1(ssa.OpITab, byteptr, v)
3579 }
3580
3581 // Have *iface.
3582 // The first word in the struct is the *itab.
3583 // If the *itab is nil, return 0.
3584 // Otherwise, the second word in the *itab is the type.
3585
3586 tab := s.newValue1(ssa.OpITab, byteptr, v)
3587 s.vars[&typVar] = tab
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003588 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
Keith Randall269baa92015-09-17 10:31:16 -07003589 b := s.endBlock()
3590 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003591 b.SetControl(isnonnil)
Keith Randall269baa92015-09-17 10:31:16 -07003592 b.Likely = ssa.BranchLikely
3593
3594 bLoad := s.f.NewBlock(ssa.BlockPlain)
3595 bEnd := s.f.NewBlock(ssa.BlockPlain)
3596
3597 b.AddEdgeTo(bLoad)
3598 b.AddEdgeTo(bEnd)
3599 bLoad.AddEdgeTo(bEnd)
3600
3601 s.startBlock(bLoad)
3602 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3603 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3604 s.endBlock()
3605
3606 s.startBlock(bEnd)
3607 typ := s.variable(&typVar, byteptr)
3608 delete(s.vars, &typVar)
3609 return typ
3610}
3611
3612// dottype generates SSA for a type assertion node.
3613// commaok indicates whether to panic or return a bool.
3614// If commaok is false, resok will be nil.
3615func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3616 iface := s.expr(n.Left)
3617 typ := s.ifaceType(n.Left, iface) // actual concrete type
3618 target := s.expr(typename(n.Type)) // target type
3619 if !isdirectiface(n.Type) {
3620 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3621 Fatalf("dottype needs a direct iface type %s", n.Type)
3622 }
3623
David Chase729abfa2015-10-26 17:34:06 -04003624 if Debug_typeassert > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003625 Warnl(n.Lineno, "type assertion inlined")
David Chase729abfa2015-10-26 17:34:06 -04003626 }
3627
Keith Randall269baa92015-09-17 10:31:16 -07003628 // TODO: If we have a nonempty interface and its itab field is nil,
3629 // then this test is redundant and ifaceType should just branch directly to bFail.
3630 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3631 b := s.endBlock()
3632 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003633 b.SetControl(cond)
Keith Randall269baa92015-09-17 10:31:16 -07003634 b.Likely = ssa.BranchLikely
3635
3636 byteptr := Ptrto(Types[TUINT8])
3637
3638 bOk := s.f.NewBlock(ssa.BlockPlain)
3639 bFail := s.f.NewBlock(ssa.BlockPlain)
3640 b.AddEdgeTo(bOk)
3641 b.AddEdgeTo(bFail)
3642
3643 if !commaok {
3644 // on failure, panic by calling panicdottype
3645 s.startBlock(bFail)
Keith Randall269baa92015-09-17 10:31:16 -07003646 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07003647 s.rtcall(panicdottype, false, nil, typ, target, taddr)
Keith Randall269baa92015-09-17 10:31:16 -07003648
3649 // on success, return idata field
3650 s.startBlock(bOk)
3651 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3652 }
3653
3654 // commaok is the more complicated case because we have
3655 // a control flow merge point.
3656 bEnd := s.f.NewBlock(ssa.BlockPlain)
3657
3658 // type assertion succeeded
3659 s.startBlock(bOk)
3660 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3661 s.vars[&okVar] = s.constBool(true)
3662 s.endBlock()
3663 bOk.AddEdgeTo(bEnd)
3664
3665 // type assertion failed
3666 s.startBlock(bFail)
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003667 s.vars[&idataVar] = s.constNil(byteptr)
Keith Randall269baa92015-09-17 10:31:16 -07003668 s.vars[&okVar] = s.constBool(false)
3669 s.endBlock()
3670 bFail.AddEdgeTo(bEnd)
3671
3672 // merge point
3673 s.startBlock(bEnd)
3674 res = s.variable(&idataVar, byteptr)
3675 resok = s.variable(&okVar, Types[TBOOL])
3676 delete(s.vars, &idataVar)
3677 delete(s.vars, &okVar)
3678 return res, resok
3679}
3680
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003681// checkgoto checks that a goto from from to to does not
3682// jump into a block or jump over variable declarations.
3683// It is a copy of checkgoto in the pre-SSA backend,
3684// modified only for line number handling.
3685// TODO: document how this works and why it is designed the way it is.
3686func (s *state) checkgoto(from *Node, to *Node) {
3687 if from.Sym == to.Sym {
3688 return
3689 }
3690
3691 nf := 0
3692 for fs := from.Sym; fs != nil; fs = fs.Link {
3693 nf++
3694 }
3695 nt := 0
3696 for fs := to.Sym; fs != nil; fs = fs.Link {
3697 nt++
3698 }
3699 fs := from.Sym
3700 for ; nf > nt; nf-- {
3701 fs = fs.Link
3702 }
3703 if fs != to.Sym {
3704 // decide what to complain about.
3705 // prefer to complain about 'into block' over declarations,
3706 // so scan backward to find most recent block or else dcl.
3707 var block *Sym
3708
3709 var dcl *Sym
3710 ts := to.Sym
3711 for ; nt > nf; nt-- {
3712 if ts.Pkg == nil {
3713 block = ts
3714 } else {
3715 dcl = ts
3716 }
3717 ts = ts.Link
3718 }
3719
3720 for ts != fs {
3721 if ts.Pkg == nil {
3722 block = ts
3723 } else {
3724 dcl = ts
3725 }
3726 ts = ts.Link
3727 fs = fs.Link
3728 }
3729
Robert Griesemerb83f3972016-03-02 11:01:25 -08003730 lno := from.Left.Lineno
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003731 if block != nil {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003732 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003733 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003734 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 -07003735 }
3736 }
3737}
3738
Keith Randalld2fd43a2015-04-15 15:51:25 -07003739// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -07003740func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003741 v := s.vars[name]
3742 if v == nil {
Keith Randall8f22b522015-06-11 21:29:25 -07003743 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randallb5c5efd2016-01-14 16:02:23 -08003744 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003745 s.vars[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003746 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003747 }
3748 return v
3749}
3750
Keith Randallcfc2aa52015-05-18 16:44:20 -07003751func (s *state) mem() *ssa.Value {
Keith Randallb32217a2015-09-17 16:45:10 -07003752 return s.variable(&memVar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003753}
3754
Keith Randallcfc2aa52015-05-18 16:44:20 -07003755func (s *state) linkForwardReferences() {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003756 // Build SSA graph. Each variable on its first use in a basic block
Keith Randalld2fd43a2015-04-15 15:51:25 -07003757 // leaves a FwdRef in that block representing the incoming value
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003758 // of that variable. This function links that ref up with possible definitions,
3759 // inserting Phi values as needed. This is essentially the algorithm
Keith Randallb5c5efd2016-01-14 16:02:23 -08003760 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
Keith Randalld2fd43a2015-04-15 15:51:25 -07003761 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
Keith Randallb5c5efd2016-01-14 16:02:23 -08003762 // Differences:
3763 // - We use FwdRef nodes to postpone phi building until the CFG is
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003764 // completely built. That way we can avoid the notion of "sealed"
Keith Randallb5c5efd2016-01-14 16:02:23 -08003765 // blocks.
3766 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3767 for len(s.fwdRefs) > 0 {
3768 v := s.fwdRefs[len(s.fwdRefs)-1]
3769 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3770 s.resolveFwdRef(v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003771 }
3772}
3773
Keith Randallb5c5efd2016-01-14 16:02:23 -08003774// resolveFwdRef modifies v to be the variable's value at the start of its block.
3775// v must be a FwdRef op.
3776func (s *state) resolveFwdRef(v *ssa.Value) {
3777 b := v.Block
3778 name := v.Aux.(*Node)
3779 v.Aux = nil
Keith Randalld2fd43a2015-04-15 15:51:25 -07003780 if b == s.f.Entry {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003781 // Live variable at start of function.
Keith Randall6a8a9da2016-02-27 17:49:31 -08003782 if s.canSSA(name) {
David Chasec3b3e7b2016-04-08 13:33:43 -04003783 if strings.HasPrefix(name.Sym.Name, "autotmp_") {
3784 // It's likely that this is an uninitialized variable in the entry block.
3785 s.Fatalf("Treating auto as if it were arg, func %s, node %v, value %v", b.Func.Name, name, v)
3786 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003787 v.Op = ssa.OpArg
3788 v.Aux = name
3789 return
Keith Randall02f4d0a2015-11-02 08:10:26 -08003790 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003791 // Not SSAable. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -07003792 addr := s.decladdrs[name]
3793 if addr == nil {
3794 // TODO: closure args reach here.
David Chase32ffbf72015-10-08 17:14:12 -04003795 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
Keith Randall8c46aa52015-06-19 21:02:28 -07003796 }
3797 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3798 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3799 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003800 v.Op = ssa.OpLoad
3801 v.AddArgs(addr, s.startmem)
3802 return
Keith Randalld2fd43a2015-04-15 15:51:25 -07003803 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003804 if len(b.Preds) == 0 {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003805 // This block is dead; we have no predecessors and we're not the entry block.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003806 // It doesn't matter what we use here as long as it is well-formed.
3807 v.Op = ssa.OpUnknown
3808 return
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003809 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003810 // Find variable value on each predecessor.
3811 var argstore [4]*ssa.Value
3812 args := argstore[:0]
3813 for _, p := range b.Preds {
3814 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
Keith Randalld2fd43a2015-04-15 15:51:25 -07003815 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003816
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003817 // Decide if we need a phi or not. We need a phi if there
Keith Randallb5c5efd2016-01-14 16:02:23 -08003818 // are two different args (which are both not v).
3819 var w *ssa.Value
3820 for _, a := range args {
3821 if a == v {
3822 continue // self-reference
3823 }
3824 if a == w {
3825 continue // already have this witness
3826 }
3827 if w != nil {
3828 // two witnesses, need a phi value
3829 v.Op = ssa.OpPhi
3830 v.AddArgs(args...)
3831 return
3832 }
3833 w = a // save witness
3834 }
3835 if w == nil {
3836 s.Fatalf("no witness for reachable phi %s", v)
3837 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003838 // One witness. Make v a copy of w.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003839 v.Op = ssa.OpCopy
3840 v.AddArg(w)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003841}
3842
3843// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003844func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003845 m := s.defvars[b.ID]
3846 if v, ok := m[name]; ok {
3847 return v
3848 }
3849 // The variable is not defined by b and we haven't
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003850 // looked it up yet. Generate a FwdRef for the variable and return that.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003851 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3852 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003853 m[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003854 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003855 return v
3856}
3857
Keith Randallc24681a2015-10-22 14:22:38 -07003858func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3859 if n.Class == Pxxx {
3860 // Don't track our dummy nodes (&memVar etc.).
3861 return
3862 }
Keith Randallc24681a2015-10-22 14:22:38 -07003863 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3864 // Don't track autotmp_ variables.
3865 return
3866 }
Keith Randall31d13f42016-03-08 20:09:48 -08003867 if n.Class == PPARAMOUT {
3868 // Don't track named output values. This prevents return values
3869 // from being assigned too early. See #14591 and #14762. TODO: allow this.
3870 return
3871 }
Keith Randallc24681a2015-10-22 14:22:38 -07003872 if n.Class == PAUTO && n.Xoffset != 0 {
3873 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3874 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003875 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3876 values, ok := s.f.NamedValues[loc]
Keith Randallc24681a2015-10-22 14:22:38 -07003877 if !ok {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003878 s.f.Names = append(s.f.Names, loc)
Keith Randallc24681a2015-10-22 14:22:38 -07003879 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003880 s.f.NamedValues[loc] = append(values, v)
Keith Randallc24681a2015-10-22 14:22:38 -07003881}
3882
Michael Pratta4e31d42016-03-12 14:07:40 -08003883// Branch is an unresolved branch.
3884type Branch struct {
3885 P *obj.Prog // branch instruction
3886 B *ssa.Block // target
Keith Randall083a6462015-05-12 11:06:44 -07003887}
3888
Michael Pratta4e31d42016-03-12 14:07:40 -08003889// SSAGenState contains state needed during Prog generation.
3890type SSAGenState struct {
3891 // Branches remembers all the branch instructions we've seen
Keith Randall9569b952015-08-28 22:51:01 -07003892 // and where they would like to go.
Michael Pratta4e31d42016-03-12 14:07:40 -08003893 Branches []Branch
Keith Randall9569b952015-08-28 22:51:01 -07003894
3895 // bstart remembers where each block starts (indexed by block ID)
3896 bstart []*obj.Prog
Keith Randall9569b952015-08-28 22:51:01 -07003897}
3898
Michael Pratta4e31d42016-03-12 14:07:40 -08003899// Pc returns the current Prog.
3900func (s *SSAGenState) Pc() *obj.Prog {
3901 return Pc
3902}
3903
3904// SetLineno sets the current source line number.
3905func (s *SSAGenState) SetLineno(l int32) {
3906 lineno = l
3907}
3908
Keith Randall083a6462015-05-12 11:06:44 -07003909// genssa appends entries to ptxt for each instruction in f.
3910// gcargs and gclocals are filled in with pointer maps for the frame.
3911func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Michael Pratta4e31d42016-03-12 14:07:40 -08003912 var s SSAGenState
Keith Randall9569b952015-08-28 22:51:01 -07003913
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003914 e := f.Config.Frontend().(*ssaExport)
3915 // We're about to emit a bunch of Progs.
3916 // Since the only way to get here is to explicitly request it,
3917 // just fail on unimplemented instead of trying to unwind our mess.
3918 e.mustImplement = true
3919
Keith Randall083a6462015-05-12 11:06:44 -07003920 // Remember where each block starts.
Keith Randall9569b952015-08-28 22:51:01 -07003921 s.bstart = make([]*obj.Prog, f.NumBlocks())
Keith Randall083a6462015-05-12 11:06:44 -07003922
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003923 var valueProgs map[*obj.Prog]*ssa.Value
3924 var blockProgs map[*obj.Prog]*ssa.Block
Dave Cheneycb1f2af2016-03-17 13:46:43 +11003925 var logProgs = e.log
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003926 if logProgs {
3927 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3928 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3929 f.Logf("genssa %s\n", f.Name)
3930 blockProgs[Pc] = f.Blocks[0]
3931 }
3932
Keith Randall083a6462015-05-12 11:06:44 -07003933 // Emit basic blocks
3934 for i, b := range f.Blocks {
Keith Randall9569b952015-08-28 22:51:01 -07003935 s.bstart[b.ID] = Pc
Keith Randall083a6462015-05-12 11:06:44 -07003936 // Emit values in block
Michael Pratta4e31d42016-03-12 14:07:40 -08003937 Thearch.SSAMarkMoves(&s, b)
Keith Randall083a6462015-05-12 11:06:44 -07003938 for _, v := range b.Values {
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003939 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003940 Thearch.SSAGenValue(&s, v)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003941 if logProgs {
3942 for ; x != Pc; x = x.Link {
3943 valueProgs[x] = v
3944 }
3945 }
Keith Randall083a6462015-05-12 11:06:44 -07003946 }
3947 // Emit control flow instructions for block
3948 var next *ssa.Block
Keith Randall91f69c62016-02-26 16:32:01 -08003949 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
Keith Randall8906d2a2016-02-22 23:19:00 -08003950 // If -N, leave next==nil so every block with successors
Keith Randall91f69c62016-02-26 16:32:01 -08003951 // ends in a JMP (except call blocks - plive doesn't like
3952 // select{send,recv} followed by a JMP call). Helps keep
3953 // line numbers for otherwise empty blocks.
Keith Randall083a6462015-05-12 11:06:44 -07003954 next = f.Blocks[i+1]
3955 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003956 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003957 Thearch.SSAGenBlock(&s, b, next)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003958 if logProgs {
3959 for ; x != Pc; x = x.Link {
3960 blockProgs[x] = b
3961 }
3962 }
Keith Randall083a6462015-05-12 11:06:44 -07003963 }
3964
3965 // Resolve branches
Michael Pratta4e31d42016-03-12 14:07:40 -08003966 for _, br := range s.Branches {
3967 br.P.To.Val = s.bstart[br.B.ID]
Keith Randall9569b952015-08-28 22:51:01 -07003968 }
Keith Randall083a6462015-05-12 11:06:44 -07003969
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003970 if logProgs {
3971 for p := ptxt; p != nil; p = p.Link {
3972 var s string
3973 if v, ok := valueProgs[p]; ok {
3974 s = v.String()
3975 } else if b, ok := blockProgs[p]; ok {
3976 s = b.String()
3977 } else {
3978 s = " " // most value and branch strings are 2-3 characters long
3979 }
3980 f.Logf("%s\t%s\n", s, p)
3981 }
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003982 if f.Config.HTML != nil {
3983 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3984 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3985 var buf bytes.Buffer
3986 buf.WriteString("<code>")
3987 buf.WriteString("<dl class=\"ssa-gen\">")
3988 for p := ptxt; p != nil; p = p.Link {
3989 buf.WriteString("<dt class=\"ssa-prog-src\">")
3990 if v, ok := valueProgs[p]; ok {
3991 buf.WriteString(v.HTML())
3992 } else if b, ok := blockProgs[p]; ok {
3993 buf.WriteString(b.HTML())
3994 }
3995 buf.WriteString("</dt>")
3996 buf.WriteString("<dd class=\"ssa-prog\">")
3997 buf.WriteString(html.EscapeString(p.String()))
3998 buf.WriteString("</dd>")
3999 buf.WriteString("</li>")
4000 }
4001 buf.WriteString("</dl>")
4002 buf.WriteString("</code>")
4003 f.Config.HTML.WriteColumn("genssa", buf.String())
4004 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
4005 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07004006 }
4007
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07004008 // Emit static data
4009 if f.StaticData != nil {
4010 for _, n := range f.StaticData.([]*Node) {
4011 if !gen_as_init(n, false) {
Keith Randall0ec72b62015-09-08 15:42:53 -07004012 Fatalf("non-static data marked as static: %v\n\n", n, f)
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07004013 }
4014 }
4015 }
4016
Keith Randalld2107fc2015-08-24 02:16:19 -07004017 // Allocate stack frame
4018 allocauto(ptxt)
Keith Randall083a6462015-05-12 11:06:44 -07004019
Keith Randalld2107fc2015-08-24 02:16:19 -07004020 // Generate gc bitmaps.
4021 liveness(Curfn, ptxt, gcargs, gclocals)
4022 gcsymdup(gcargs)
4023 gcsymdup(gclocals)
Keith Randall083a6462015-05-12 11:06:44 -07004024
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004025 // Add frame prologue. Zero ambiguously live variables.
Keith Randalld2107fc2015-08-24 02:16:19 -07004026 Thearch.Defframe(ptxt)
4027 if Debug['f'] != 0 {
4028 frame(0)
4029 }
4030
4031 // Remove leftover instrumentation from the instruction stream.
4032 removevardef(ptxt)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07004033
4034 f.Config.HTML.Close()
Keith Randall083a6462015-05-12 11:06:44 -07004035}
4036
Daniel Morsing66b47812015-06-27 15:45:20 +01004037// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
Matthew Dempsky0d9258a2016-03-07 18:00:08 -08004038func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
Daniel Morsing66b47812015-06-27 15:45:20 +01004039 p := Prog(as)
4040 // TODO: use zero register on archs that support it.
4041 p.From.Type = obj.TYPE_CONST
4042 p.From.Offset = 0
4043 p.To.Type = obj.TYPE_MEM
4044 p.To.Reg = regnum
4045 p.To.Offset = offset
4046 offset += width
4047 nleft = nbytes - width
4048 return nleft, offset
4049}
4050
Michael Pratta4e31d42016-03-12 14:07:40 -08004051type FloatingEQNEJump struct {
4052 Jump obj.As
4053 Index int
David Chase8e601b22015-08-18 14:39:26 -04004054}
4055
Michael Pratta4e31d42016-03-12 14:07:40 -08004056func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
4057 p := Prog(jumps.Jump)
David Chase8e601b22015-08-18 14:39:26 -04004058 p.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08004059 to := jumps.Index
4060 branches = append(branches, Branch{p, b.Succs[to]})
David Chase8e601b22015-08-18 14:39:26 -04004061 if to == 1 {
4062 likely = -likely
4063 }
4064 // liblink reorders the instruction stream as it sees fit.
4065 // Pass along what we know so liblink can make use of it.
4066 // TODO: Once we've fully switched to SSA,
4067 // make liblink leave our output alone.
4068 switch likely {
4069 case ssa.BranchUnlikely:
4070 p.From.Type = obj.TYPE_CONST
4071 p.From.Offset = 0
4072 case ssa.BranchLikely:
4073 p.From.Type = obj.TYPE_CONST
4074 p.From.Offset = 1
4075 }
4076 return branches
4077}
4078
Michael Pratta4e31d42016-03-12 14:07:40 -08004079func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
David Chase8e601b22015-08-18 14:39:26 -04004080 likely := b.Likely
4081 switch next {
4082 case b.Succs[0]:
Michael Pratta4e31d42016-03-12 14:07:40 -08004083 s.Branches = oneFPJump(b, &jumps[0][0], likely, s.Branches)
4084 s.Branches = oneFPJump(b, &jumps[0][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04004085 case b.Succs[1]:
Michael Pratta4e31d42016-03-12 14:07:40 -08004086 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
4087 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04004088 default:
Michael Pratta4e31d42016-03-12 14:07:40 -08004089 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
4090 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04004091 q := Prog(obj.AJMP)
4092 q.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08004093 s.Branches = append(s.Branches, Branch{q, b.Succs[1]})
David Chase8e601b22015-08-18 14:39:26 -04004094 }
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004095}
4096
Michael Pratta4e31d42016-03-12 14:07:40 -08004097// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4098func AddAux(a *obj.Addr, v *ssa.Value) {
4099 AddAux2(a, v, v.AuxInt)
Keith Randall083a6462015-05-12 11:06:44 -07004100}
Michael Pratta4e31d42016-03-12 14:07:40 -08004101func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
Keith Randall8c46aa52015-06-19 21:02:28 -07004102 if a.Type != obj.TYPE_MEM {
Michael Pratta4e31d42016-03-12 14:07:40 -08004103 v.Fatalf("bad AddAux addr %s", a)
Keith Randall8c46aa52015-06-19 21:02:28 -07004104 }
4105 // add integer offset
Keith Randalld43f2e32015-10-21 13:13:56 -07004106 a.Offset += offset
Keith Randall8c46aa52015-06-19 21:02:28 -07004107
4108 // If no additional symbol offset, we're done.
4109 if v.Aux == nil {
4110 return
4111 }
4112 // Add symbol's offset from its base register.
4113 switch sym := v.Aux.(type) {
4114 case *ssa.ExternSymbol:
4115 a.Name = obj.NAME_EXTERN
Ian Lance Taylor65b40202016-03-16 22:22:58 -07004116 switch s := sym.Sym.(type) {
4117 case *Sym:
4118 a.Sym = Linksym(s)
4119 case *obj.LSym:
4120 a.Sym = s
4121 default:
4122 v.Fatalf("ExternSymbol.Sym is %T", s)
4123 }
Keith Randall8c46aa52015-06-19 21:02:28 -07004124 case *ssa.ArgSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004125 n := sym.Node.(*Node)
4126 a.Name = obj.NAME_PARAM
4127 a.Node = n
4128 a.Sym = Linksym(n.Orig.Sym)
4129 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 -07004130 case *ssa.AutoSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004131 n := sym.Node.(*Node)
4132 a.Name = obj.NAME_AUTO
4133 a.Node = n
4134 a.Sym = Linksym(n.Sym)
Keith Randall8c46aa52015-06-19 21:02:28 -07004135 default:
4136 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4137 }
4138}
4139
Keith Randall582baae2015-11-02 21:28:13 -08004140// extendIndex extends v to a full int width.
Keith Randall2a5e6c42015-07-23 14:35:02 -07004141func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4142 size := v.Type.Size()
Keith Randall582baae2015-11-02 21:28:13 -08004143 if size == s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004144 return v
4145 }
Keith Randall582baae2015-11-02 21:28:13 -08004146 if size > s.config.IntSize {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004147 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
Keith Randall2a5e6c42015-07-23 14:35:02 -07004148 // the high word and branch to out-of-bounds failure if it is not 0.
4149 s.Unimplementedf("64->32 index truncation not implemented")
4150 return v
4151 }
4152
4153 // Extend value to the required size
4154 var op ssa.Op
4155 if v.Type.IsSigned() {
Keith Randall582baae2015-11-02 21:28:13 -08004156 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004157 case 14:
4158 op = ssa.OpSignExt8to32
4159 case 18:
4160 op = ssa.OpSignExt8to64
4161 case 24:
4162 op = ssa.OpSignExt16to32
4163 case 28:
4164 op = ssa.OpSignExt16to64
4165 case 48:
4166 op = ssa.OpSignExt32to64
4167 default:
4168 s.Fatalf("bad signed index extension %s", v.Type)
4169 }
4170 } else {
Keith Randall582baae2015-11-02 21:28:13 -08004171 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004172 case 14:
4173 op = ssa.OpZeroExt8to32
4174 case 18:
4175 op = ssa.OpZeroExt8to64
4176 case 24:
4177 op = ssa.OpZeroExt16to32
4178 case 28:
4179 op = ssa.OpZeroExt16to64
4180 case 48:
4181 op = ssa.OpZeroExt32to64
4182 default:
4183 s.Fatalf("bad unsigned index extension %s", v.Type)
4184 }
4185 }
Keith Randall582baae2015-11-02 21:28:13 -08004186 return s.newValue1(op, Types[TINT], v)
Keith Randall2a5e6c42015-07-23 14:35:02 -07004187}
4188
Michael Pratta4e31d42016-03-12 14:07:40 -08004189// SSARegNum returns the register (in cmd/internal/obj numbering) to
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004190// which v has been allocated. Panics if v is not assigned to a
Keith Randall083a6462015-05-12 11:06:44 -07004191// register.
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004192// TODO: Make this panic again once it stops happening routinely.
Michael Pratta4e31d42016-03-12 14:07:40 -08004193func SSARegNum(v *ssa.Value) int16 {
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004194 reg := v.Block.Func.RegAlloc[v.ID]
4195 if reg == nil {
4196 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
4197 return 0
4198 }
Michael Pratta4e31d42016-03-12 14:07:40 -08004199 return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
Keith Randall083a6462015-05-12 11:06:44 -07004200}
4201
Michael Pratta4e31d42016-03-12 14:07:40 -08004202// AutoVar returns a *Node and int64 representing the auto variable and offset within it
Keith Randall02f4d0a2015-11-02 08:10:26 -08004203// where v should be spilled.
Michael Pratta4e31d42016-03-12 14:07:40 -08004204func AutoVar(v *ssa.Value) (*Node, int64) {
Keith Randall02f4d0a2015-11-02 08:10:26 -08004205 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
Keith Randall9094e3a2016-01-04 13:34:54 -08004206 if v.Type.Size() > loc.Type.Size() {
4207 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
4208 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08004209 return loc.N.(*Node), loc.Off
Keith Randall083a6462015-05-12 11:06:44 -07004210}
Keith Randallf7f604e2015-05-27 14:52:22 -07004211
Keith Randalla734bbc2016-01-11 21:05:33 -08004212// fieldIdx finds the index of the field referred to by the ODOT node n.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07004213func fieldIdx(n *Node) int {
Keith Randalla734bbc2016-01-11 21:05:33 -08004214 t := n.Left.Type
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07004215 f := n.Sym
Matthew Dempsky3efefd92016-03-30 14:56:08 -07004216 if !t.IsStruct() {
Keith Randalla734bbc2016-01-11 21:05:33 -08004217 panic("ODOT's LHS is not a struct")
4218 }
4219
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07004220 var i int
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07004221 for _, t1 := range t.Fields().Slice() {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07004222 if t1.Sym != f {
Keith Randalla734bbc2016-01-11 21:05:33 -08004223 i++
4224 continue
4225 }
Matthew Dempsky62dddd42016-03-28 09:40:53 -07004226 if t1.Offset != n.Xoffset {
Keith Randalla734bbc2016-01-11 21:05:33 -08004227 panic("field offset doesn't match")
4228 }
4229 return i
4230 }
4231 panic(fmt.Sprintf("can't find field in expr %s\n", n))
4232
Eric Engestrom7a8caf72016-04-03 12:43:27 +01004233 // TODO: keep the result of this function somewhere in the ODOT Node
Keith Randalla734bbc2016-01-11 21:05:33 -08004234 // so we don't have to recompute it each time we need it.
4235}
4236
Keith Randallf7f604e2015-05-27 14:52:22 -07004237// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004238type ssaExport struct {
4239 log bool
4240 unimplemented bool
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004241 mustImplement bool
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004242}
Keith Randallf7f604e2015-05-27 14:52:22 -07004243
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004244func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
4245func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
4246func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
4247func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
4248func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
4249func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
4250func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
4251func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
4252func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
David Chase52578582015-08-28 14:24:10 -04004253func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
4254func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004255func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
4256func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
4257func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
4258func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
4259
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004260// StringData returns a symbol (a *Sym wrapped in an interface) which
4261// is the data component of a global string constant containing s.
4262func (*ssaExport) StringData(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07004263 // TODO: is idealstring correct? It might not matter...
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004264 _, data := stringsym(s)
4265 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
Keith Randallf7f604e2015-05-27 14:52:22 -07004266}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004267
Keith Randallc24681a2015-10-22 14:22:38 -07004268func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
Keith Randalld2107fc2015-08-24 02:16:19 -07004269 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
4270 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
4271 return n
4272}
4273
Keith Randall4a7aba72016-03-28 11:25:17 -07004274func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4275 n := name.N.(*Node)
4276 ptrType := Ptrto(Types[TUINT8])
4277 lenType := Types[TINT]
4278 if n.Class == PAUTO && !n.Addrtaken {
4279 // Split this string up into two separate variables.
4280 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4281 l := e.namedAuto(n.Sym.Name+".len", lenType)
4282 return ssa.LocalSlot{p, ptrType, 0}, ssa.LocalSlot{l, lenType, 0}
4283 }
4284 // Return the two parts of the larger variable.
4285 return ssa.LocalSlot{n, ptrType, name.Off}, ssa.LocalSlot{n, lenType, name.Off + int64(Widthptr)}
4286}
4287
4288func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4289 n := name.N.(*Node)
4290 t := Ptrto(Types[TUINT8])
4291 if n.Class == PAUTO && !n.Addrtaken {
4292 // Split this interface up into two separate variables.
4293 f := ".itab"
Matthew Dempsky00e5a682016-04-01 13:36:24 -07004294 if n.Type.IsEmptyInterface() {
Keith Randall4a7aba72016-03-28 11:25:17 -07004295 f = ".type"
4296 }
4297 c := e.namedAuto(n.Sym.Name+f, t)
4298 d := e.namedAuto(n.Sym.Name+".data", t)
4299 return ssa.LocalSlot{c, t, 0}, ssa.LocalSlot{d, t, 0}
4300 }
4301 // Return the two parts of the larger variable.
4302 return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + int64(Widthptr)}
4303}
4304
4305func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
4306 n := name.N.(*Node)
Keith Randallb04e1452016-03-31 21:24:10 -07004307 ptrType := Ptrto(name.Type.ElemType().(*Type))
Keith Randall4a7aba72016-03-28 11:25:17 -07004308 lenType := Types[TINT]
4309 if n.Class == PAUTO && !n.Addrtaken {
4310 // Split this slice up into three separate variables.
4311 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4312 l := e.namedAuto(n.Sym.Name+".len", lenType)
4313 c := e.namedAuto(n.Sym.Name+".cap", lenType)
4314 return ssa.LocalSlot{p, ptrType, 0}, ssa.LocalSlot{l, lenType, 0}, ssa.LocalSlot{c, lenType, 0}
4315 }
4316 // Return the three parts of the larger variable.
4317 return ssa.LocalSlot{n, ptrType, name.Off},
4318 ssa.LocalSlot{n, lenType, name.Off + int64(Widthptr)},
4319 ssa.LocalSlot{n, lenType, name.Off + int64(2*Widthptr)}
4320}
4321
4322func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4323 n := name.N.(*Node)
4324 s := name.Type.Size() / 2
4325 var t *Type
4326 if s == 8 {
4327 t = Types[TFLOAT64]
4328 } else {
4329 t = Types[TFLOAT32]
4330 }
4331 if n.Class == PAUTO && !n.Addrtaken {
4332 // Split this complex up into two separate variables.
4333 c := e.namedAuto(n.Sym.Name+".real", t)
4334 d := e.namedAuto(n.Sym.Name+".imag", t)
4335 return ssa.LocalSlot{c, t, 0}, ssa.LocalSlot{d, t, 0}
4336 }
4337 // Return the two parts of the larger variable.
4338 return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + s}
4339}
4340
Keith Randallb04e1452016-03-31 21:24:10 -07004341func (e *ssaExport) SplitStruct(name ssa.LocalSlot, i int) ssa.LocalSlot {
4342 n := name.N.(*Node)
4343 st := name.Type
4344 ft := st.FieldType(i)
4345 if n.Class == PAUTO && !n.Addrtaken {
4346 // Note: the _ field may appear several times. But
4347 // have no fear, identically-named but distinct Autos are
4348 // ok, albeit maybe confusing for a debugger.
4349 x := e.namedAuto(n.Sym.Name+"."+st.FieldName(i), ft)
4350 return ssa.LocalSlot{x, ft, 0}
4351 }
4352 return ssa.LocalSlot{n, ft, name.Off + st.FieldOff(i)}
4353}
4354
Keith Randall4a7aba72016-03-28 11:25:17 -07004355// namedAuto returns a new AUTO variable with the given name and type.
4356func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
4357 t := typ.(*Type)
4358 s := Lookup(name)
4359 n := Nod(ONAME, nil, nil)
4360 s.Def = n
4361 s.Def.Used = true
4362 n.Sym = s
4363 n.Type = t
4364 n.Class = PAUTO
4365 n.Addable = true
4366 n.Ullman = 1
4367 n.Esc = EscNever
4368 n.Xoffset = 0
4369 n.Name.Curfn = Curfn
4370 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
4371
4372 dowidth(t)
4373 e.mustImplement = true
4374
4375 return n
4376}
4377
Keith Randall7d612462015-10-22 13:07:38 -07004378func (e *ssaExport) CanSSA(t ssa.Type) bool {
Keith Randall37590bd2015-09-18 22:58:10 -07004379 return canSSAType(t.(*Type))
4380}
4381
Keith Randallb5c5efd2016-01-14 16:02:23 -08004382func (e *ssaExport) Line(line int32) string {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08004383 return linestr(line)
Keith Randallb5c5efd2016-01-14 16:02:23 -08004384}
4385
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004386// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004387func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004388 // If e was marked as unimplemented, anything could happen. Ignore.
4389 if e.log && !e.unimplemented {
4390 fmt.Printf(msg, args...)
4391 }
4392}
4393
David Chase88b230e2016-01-29 14:44:15 -05004394func (e *ssaExport) Log() bool {
4395 return e.log
4396}
4397
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004398// Fatal reports a compiler error and exits.
Keith Randallda8af472016-01-13 11:14:57 -08004399func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004400 // If e was marked as unimplemented, anything could happen. Ignore.
4401 if !e.unimplemented {
Keith Randallda8af472016-01-13 11:14:57 -08004402 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004403 Fatalf(msg, args...)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004404 }
4405}
4406
4407// Unimplemented reports that the function cannot be compiled.
4408// It will be removed once SSA work is complete.
Keith Randallda8af472016-01-13 11:14:57 -08004409func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004410 if e.mustImplement {
Keith Randallda8af472016-01-13 11:14:57 -08004411 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004412 Fatalf(msg, args...)
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004413 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004414 const alwaysLog = false // enable to calculate top unimplemented features
4415 if !e.unimplemented && (e.log || alwaysLog) {
4416 // first implementation failure, print explanation
4417 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4418 }
4419 e.unimplemented = true
4420}
Keith Randallc24681a2015-10-22 14:22:38 -07004421
David Chase729abfa2015-10-26 17:34:06 -04004422// Warnl reports a "warning", which is usually flag-triggered
4423// logging output for the benefit of tests.
Todd Neal98b88de2016-03-13 23:04:31 -05004424func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
4425 Warnl(line, fmt_, args...)
David Chase729abfa2015-10-26 17:34:06 -04004426}
4427
4428func (e *ssaExport) Debug_checknil() bool {
4429 return Debug_checknil != 0
4430}
4431
Keith Randallc24681a2015-10-22 14:22:38 -07004432func (n *Node) Typ() ssa.Type {
4433 return n.Type
4434}