blob: bfac175975736c06a32ea4f59bf10ceed709ea39 [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"
Keith Randalld2fd43a2015-04-15 15:51:25 -070016)
17
Keith Randallc0740fe2016-03-03 22:06:57 -080018var ssaEnabled = true
19
Keith Randall2f57d0f2016-01-28 13:46:30 -080020var ssaConfig *ssa.Config
21var ssaExp ssaExport
22
David Chase378a8632016-02-25 13:10:51 -050023func initssa() *ssa.Config {
24 ssaExp.unimplemented = false
25 ssaExp.mustImplement = true
26 if ssaConfig == nil {
27 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
28 }
29 return ssaConfig
30}
31
Keith Randall5b355a72015-12-11 20:41:52 -080032func shouldssa(fn *Node) bool {
Keith Randall4c9a4702016-03-21 22:57:26 -070033 switch Thearch.Thestring {
34 default:
35 // Only available for testing.
36 if os.Getenv("SSATEST") == "" {
37 return false
38 }
39 // Generally available.
40 case "amd64":
Keith Randall5b355a72015-12-11 20:41:52 -080041 }
Keith Randallc0740fe2016-03-03 22:06:57 -080042 if !ssaEnabled {
43 return false
44 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070045
David Chasee99dd522015-10-19 11:36:07 -040046 // Environment variable control of SSA CG
47 // 1. IF GOSSAFUNC == current function name THEN
48 // compile this function with SSA and log output to ssa.html
49
David Chase729abfa2015-10-26 17:34:06 -040050 // 2. IF GOSSAHASH == "" THEN
David Chasee99dd522015-10-19 11:36:07 -040051 // compile this function (and everything else) with SSA
52
David Chase729abfa2015-10-26 17:34:06 -040053 // 3. IF GOSSAHASH == "n" or "N"
David Chasee99dd522015-10-19 11:36:07 -040054 // IF GOSSAPKG == current package name THEN
55 // compile this function (and everything in this package) with SSA
56 // ELSE
57 // use the old back end for this function.
58 // This is for compatibility with existing test harness and should go away.
59
60 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
61 // compile this function with SSA
62 // ELSE
63 // compile this function with the old back end.
64
David Chase729abfa2015-10-26 17:34:06 -040065 // Plan is for 3 to be removed when the tests are revised.
66 // SSA is now default, and is disabled by setting
67 // GOSSAHASH to n or N, or selectively with strings of
68 // 0 and 1.
David Chasee99dd522015-10-19 11:36:07 -040069
Keith Randall5b355a72015-12-11 20:41:52 -080070 name := fn.Func.Nname.Sym.Name
71
72 funcname := os.Getenv("GOSSAFUNC")
73 if funcname != "" {
74 // If GOSSAFUNC is set, compile only that function.
75 return name == funcname
76 }
77
78 pkg := os.Getenv("GOSSAPKG")
79 if pkg != "" {
80 // If GOSSAPKG is set, compile only that package.
81 return localpkg.Name == pkg
82 }
83
David Chase378a8632016-02-25 13:10:51 -050084 return initssa().DebugHashMatch("GOSSAHASH", name)
Keith Randall5b355a72015-12-11 20:41:52 -080085}
86
87// buildssa builds an SSA function.
88func buildssa(fn *Node) *ssa.Func {
89 name := fn.Func.Nname.Sym.Name
Keith Randall59681802016-03-01 13:47:48 -080090 printssa := name == os.Getenv("GOSSAFUNC")
Keith Randall5b355a72015-12-11 20:41:52 -080091 if printssa {
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -070092 fmt.Println("generating SSA for", name)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080093 dumplist("buildssa-enter", fn.Func.Enter)
94 dumplist("buildssa-body", fn.Nbody)
95 dumplist("buildssa-exit", fn.Func.Exit)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070096 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070097
Keith Randallcfc2aa52015-05-18 16:44:20 -070098 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -040099 s.pushLine(fn.Lineno)
100 defer s.popLine()
101
Keith Randall6a8a9da2016-02-27 17:49:31 -0800102 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
103 s.cgoUnsafeArgs = true
104 }
Keith Randall15ed37d2016-03-16 21:51:17 -0700105 if fn.Func.Pragma&Nowritebarrier != 0 {
106 s.noWB = true
107 }
108 defer func() {
109 if s.WBLineno != 0 {
110 fn.Func.WBLineno = s.WBLineno
111 }
112 }()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700113 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700114
Keith Randall2f57d0f2016-01-28 13:46:30 -0800115 ssaExp.log = printssa
David Chase378a8632016-02-25 13:10:51 -0500116
117 s.config = initssa()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700118 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700119 s.f.Name = name
David Chase8824dcc2015-10-08 12:39:56 -0400120 s.exitCode = fn.Func.Exit
Keith Randall74e568f2015-11-09 21:35:40 -0800121 s.panics = map[funcLine]*ssa.Block{}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700122
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700123 if name == os.Getenv("GOSSAFUNC") {
124 // TODO: tempfile? it is handy to have the location
125 // of this file be stable, so you can just reload in the browser.
Keith Randallda8af472016-01-13 11:14:57 -0800126 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700127 // TODO: generate and print a mapping from nodes to values and blocks
128 }
129 defer func() {
Keith Randall5b355a72015-12-11 20:41:52 -0800130 if !printssa {
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700131 s.config.HTML.Close()
132 }
133 }()
134
Keith Randalld2fd43a2015-04-15 15:51:25 -0700135 // Allocate starting block
136 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
137
Keith Randallcfc2aa52015-05-18 16:44:20 -0700138 // Allocate starting values
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700139 s.labels = map[string]*ssaLabel{}
140 s.labeledNodes = map[*Node]*ssaLabel{}
Keith Randall02f4d0a2015-11-02 08:10:26 -0800141 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -0700142 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
143 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
Keith Randall8c46aa52015-06-19 21:02:28 -0700144
David Chase956f3192015-09-11 16:40:05 -0400145 s.startBlock(s.f.Entry)
146 s.vars[&memVar] = s.startmem
147
Todd Neald076ef72015-10-15 20:25:32 -0500148 s.varsyms = map[*Node]interface{}{}
149
Keith Randall8c46aa52015-06-19 21:02:28 -0700150 // Generate addresses of local declarations
151 s.decladdrs = map[*Node]*ssa.Value{}
Keith Randall4fffd4562016-02-29 13:31:48 -0800152 for _, n := range fn.Func.Dcl {
Keith Randall8c46aa52015-06-19 21:02:28 -0700153 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -0800154 case PPARAM, PPARAMOUT:
Todd Neald076ef72015-10-15 20:25:32 -0500155 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randall8c46aa52015-06-19 21:02:28 -0700156 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800157 if n.Class == PPARAMOUT && s.canSSA(n) {
158 // Save ssa-able PPARAMOUT variables so we can
159 // store them back to the stack at the end of
160 // the function.
161 s.returns = append(s.returns, n)
162 }
David Chase956f3192015-09-11 16:40:05 -0400163 case PAUTO | PHEAP:
164 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
Todd Neald076ef72015-10-15 20:25:32 -0500165 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
David Chase956f3192015-09-11 16:40:05 -0400166 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase8824dcc2015-10-08 12:39:56 -0400167 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
168 // This ends up wrong, have to do it at the PARAM node instead.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800169 case PAUTO:
Keith Randalld2107fc2015-08-24 02:16:19 -0700170 // processed at each use, to prevent Addr coming
171 // before the decl.
Keith Randallc3eb1a72015-09-06 13:42:26 -0700172 case PFUNC:
173 // local function - already handled by frontend
Daniel Morsingbe2a3e22015-07-01 20:37:25 +0100174 default:
175 str := ""
176 if n.Class&PHEAP != 0 {
177 str = ",heap"
178 }
Josh Bleecher Snyder58446032015-08-23 20:29:43 -0700179 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -0700180 }
181 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700182
183 // Convert the AST-based IR to the SSA-based IR
Keith Randall4fffd4562016-02-29 13:31:48 -0800184 s.stmts(fn.Func.Enter)
Keith Randall9d854fd2016-03-01 12:50:17 -0800185 s.stmts(fn.Nbody)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700186
Keith Randallcfc2aa52015-05-18 16:44:20 -0700187 // fallthrough to exit
Keith Randalla7cfc7592015-09-08 16:04:37 -0700188 if s.curBlock != nil {
Keith Randallddc6b642016-03-09 19:27:57 -0800189 s.pushLine(fn.Func.Endlineno)
190 s.exit()
191 s.popLine()
Keith Randallcfc2aa52015-05-18 16:44:20 -0700192 }
193
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700194 // Check that we used all labels
195 for name, lab := range s.labels {
196 if !lab.used() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800197 yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700198 lab.reported = true
199 }
200 if lab.used() && !lab.defined() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800201 yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700202 lab.reported = true
203 }
204 }
205
206 // Check any forward gotos. Non-forward gotos have already been checked.
207 for _, n := range s.fwdGotos {
208 lab := s.labels[n.Left.Sym.Name]
209 // If the label is undefined, we have already have printed an error.
210 if lab.defined() {
211 s.checkgoto(n, lab.defNode)
212 }
213 }
214
215 if nerrors > 0 {
Keith Randall4c5459d2016-01-28 16:11:56 -0800216 s.f.Free()
Keith Randall5b355a72015-12-11 20:41:52 -0800217 return nil
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700218 }
219
Keith Randalld2fd43a2015-04-15 15:51:25 -0700220 // Link up variable uses to variable definitions
221 s.linkForwardReferences()
222
David Chase8824dcc2015-10-08 12:39:56 -0400223 // Don't carry reference this around longer than necessary
Keith Randall4fffd4562016-02-29 13:31:48 -0800224 s.exitCode = Nodes{}
David Chase8824dcc2015-10-08 12:39:56 -0400225
Josh Bleecher Snyder983bc8d2015-07-17 16:47:43 +0000226 // Main call to ssa package to compile function
227 ssa.Compile(s.f)
228
Keith Randall5b355a72015-12-11 20:41:52 -0800229 return s.f
Keith Randalld2fd43a2015-04-15 15:51:25 -0700230}
231
Keith Randallcfc2aa52015-05-18 16:44:20 -0700232type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700233 // configuration (arch) information
234 config *ssa.Config
235
236 // function we're building
237 f *ssa.Func
238
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700239 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
240 labels map[string]*ssaLabel
241 labeledNodes map[*Node]*ssaLabel
242
243 // gotos that jump forward; required for deferred checkgoto calls
244 fwdGotos []*Node
David Chase8824dcc2015-10-08 12:39:56 -0400245 // Code that must precede any return
246 // (e.g., copying value of heap-escaped paramout back to true paramout)
Keith Randall4fffd4562016-02-29 13:31:48 -0800247 exitCode Nodes
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700248
249 // unlabeled break and continue statement tracking
250 breakTo *ssa.Block // current target for plain break statement
251 continueTo *ssa.Block // current target for plain continue statement
Keith Randalld2fd43a2015-04-15 15:51:25 -0700252
253 // current location where we're interpreting the AST
254 curBlock *ssa.Block
255
Keith Randall8c46aa52015-06-19 21:02:28 -0700256 // variable assignments in the current block (map from variable symbol to ssa value)
257 // *Node is the unique identifier (an ONAME Node) for the variable.
258 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700259
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000260 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700261 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700262
Keith Randalld2107fc2015-08-24 02:16:19 -0700263 // addresses of PPARAM and PPARAMOUT variables.
Keith Randall8c46aa52015-06-19 21:02:28 -0700264 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700265
Todd Neald076ef72015-10-15 20:25:32 -0500266 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
267 varsyms map[*Node]interface{}
268
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000269 // starting values. Memory, stack pointer, and globals pointer
Keith Randallcfc2aa52015-05-18 16:44:20 -0700270 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700271 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700272 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400273
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000274 // line number stack. The current line number is top of stack
Michael Matloob81ccf502015-05-30 01:03:06 -0400275 line []int32
Keith Randall74e568f2015-11-09 21:35:40 -0800276
277 // list of panic calls by function name and line number.
278 // Used to deduplicate panic calls.
279 panics map[funcLine]*ssa.Block
Keith Randallb5c5efd2016-01-14 16:02:23 -0800280
281 // list of FwdRef values.
282 fwdRefs []*ssa.Value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800283
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000284 // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800285 returns []*Node
286
287 cgoUnsafeArgs bool
Keith Randall15ed37d2016-03-16 21:51:17 -0700288 noWB bool
289 WBLineno int32 // line number of first write barrier. 0=no write barriers
Keith Randall74e568f2015-11-09 21:35:40 -0800290}
291
292type funcLine struct {
293 f *Node
294 line int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700295}
296
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700297type ssaLabel struct {
298 target *ssa.Block // block identified by this label
299 breakTarget *ssa.Block // block to break to in control flow node identified by this label
300 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
301 defNode *Node // label definition Node (OLABEL)
302 // Label use Node (OGOTO, OBREAK, OCONTINUE).
303 // Used only for error detection and reporting.
304 // There might be multiple uses, but we only need to track one.
305 useNode *Node
306 reported bool // reported indicates whether an error has already been reported for this label
307}
308
309// defined reports whether the label has a definition (OLABEL node).
310func (l *ssaLabel) defined() bool { return l.defNode != nil }
311
312// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
313func (l *ssaLabel) used() bool { return l.useNode != nil }
314
315// label returns the label associated with sym, creating it if necessary.
316func (s *state) label(sym *Sym) *ssaLabel {
317 lab := s.labels[sym.Name]
318 if lab == nil {
319 lab = new(ssaLabel)
320 s.labels[sym.Name] = lab
321 }
322 return lab
323}
324
Keith Randallda8af472016-01-13 11:14:57 -0800325func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
David Chase88b230e2016-01-29 14:44:15 -0500326func (s *state) Log() bool { return s.config.Log() }
Keith Randallda8af472016-01-13 11:14:57 -0800327func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
328func (s *state) Unimplementedf(msg string, args ...interface{}) {
329 s.config.Unimplementedf(s.peekLine(), msg, args...)
330}
Todd Neal98b88de2016-03-13 23:04:31 -0500331func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
332func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700333
Keith Randall269baa92015-09-17 10:31:16 -0700334var (
335 // dummy node for the memory variable
Keith Randallc24681a2015-10-22 14:22:38 -0700336 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
Keith Randall8c46aa52015-06-19 21:02:28 -0700337
Keith Randall269baa92015-09-17 10:31:16 -0700338 // dummy nodes for temporary variables
Keith Randallc24681a2015-10-22 14:22:38 -0700339 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
340 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
341 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
342 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
343 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
Keith Randall69a7c1522016-03-21 15:24:08 -0700344 deltaVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "delta"}}
Keith Randall269baa92015-09-17 10:31:16 -0700345)
Keith Randall5505e8c2015-09-12 23:27:26 -0700346
Keith Randalld2fd43a2015-04-15 15:51:25 -0700347// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700348func (s *state) startBlock(b *ssa.Block) {
349 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700350 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700351 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700352 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700353 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700354}
355
356// endBlock marks the end of generating code for the current block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000357// Returns the (former) current block. Returns nil if there is no current
Keith Randalld2fd43a2015-04-15 15:51:25 -0700358// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700359func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700360 b := s.curBlock
361 if b == nil {
362 return nil
363 }
364 for len(s.defvars) <= int(b.ID) {
365 s.defvars = append(s.defvars, nil)
366 }
367 s.defvars[b.ID] = s.vars
368 s.curBlock = nil
369 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400370 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700371 return b
372}
373
Michael Matloob81ccf502015-05-30 01:03:06 -0400374// pushLine pushes a line number on the line number stack.
375func (s *state) pushLine(line int32) {
376 s.line = append(s.line, line)
377}
378
379// popLine pops the top of the line number stack.
380func (s *state) popLine() {
381 s.line = s.line[:len(s.line)-1]
382}
383
384// peekLine peek the top of the line number stack.
385func (s *state) peekLine() int32 {
386 return s.line[len(s.line)-1]
387}
388
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700389func (s *state) Error(msg string, args ...interface{}) {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800390 yyerrorl(s.peekLine(), msg, args...)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700391}
392
Keith Randall8f22b522015-06-11 21:29:25 -0700393// newValue0 adds a new value with no arguments to the current block.
394func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
395 return s.curBlock.NewValue0(s.peekLine(), op, t)
396}
397
398// newValue0A adds a new value with no arguments and an aux value to the current block.
399func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
400 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400401}
402
Todd Neal991036a2015-09-03 18:24:22 -0500403// newValue0I adds a new value with no arguments and an auxint value to the current block.
404func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
405 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
406}
407
Michael Matloob81ccf502015-05-30 01:03:06 -0400408// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700409func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
410 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
411}
412
413// newValue1A adds a new value with one argument and an aux value to the current block.
414func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
415 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400416}
417
Keith Randallcd7e0592015-07-15 21:33:49 -0700418// newValue1I adds a new value with one argument and an auxint value to the current block.
419func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
420 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
421}
422
Michael Matloob81ccf502015-05-30 01:03:06 -0400423// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700424func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
425 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400426}
427
Daniel Morsing66b47812015-06-27 15:45:20 +0100428// newValue2I adds a new value with two arguments and an auxint value to the current block.
429func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
430 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
431}
432
Michael Matloob81ccf502015-05-30 01:03:06 -0400433// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700434func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
435 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400436}
437
Keith Randalld4cc51d2015-08-14 21:47:20 -0700438// newValue3I adds a new value with three arguments and an auxint value to the current block.
439func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
440 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
441}
442
Todd Neal991036a2015-09-03 18:24:22 -0500443// entryNewValue0 adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700444func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
445 return s.f.Entry.NewValue0(s.peekLine(), op, t)
446}
447
Todd Neal991036a2015-09-03 18:24:22 -0500448// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700449func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
450 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400451}
452
Todd Neal991036a2015-09-03 18:24:22 -0500453// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
454func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
455 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
456}
457
Michael Matloob81ccf502015-05-30 01:03:06 -0400458// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700459func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
460 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
461}
462
463// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
464func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
465 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400466}
467
Keith Randall8c46aa52015-06-19 21:02:28 -0700468// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
469func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
470 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
471}
472
Michael Matloob81ccf502015-05-30 01:03:06 -0400473// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700474func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
475 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400476}
477
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700478// const* routines add a new const value to the entry block.
Josh Bleecher Snyder39214272016-03-06 18:06:09 -0800479func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) }
480func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) }
481func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) }
482func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700483func (s *state) constBool(c bool) *ssa.Value {
484 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
485}
Keith Randall9cb332e2015-07-28 14:19:20 -0700486func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
487 return s.f.ConstInt8(s.peekLine(), t, c)
488}
489func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
490 return s.f.ConstInt16(s.peekLine(), t, c)
491}
492func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
493 return s.f.ConstInt32(s.peekLine(), t, c)
494}
495func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
496 return s.f.ConstInt64(s.peekLine(), t, c)
497}
David Chase997a9f32015-08-12 16:38:11 -0400498func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
499 return s.f.ConstFloat32(s.peekLine(), t, c)
500}
501func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
502 return s.f.ConstFloat64(s.peekLine(), t, c)
503}
Michael Matloob81ccf502015-05-30 01:03:06 -0400504func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
Keith Randall9cb332e2015-07-28 14:19:20 -0700505 if s.config.IntSize == 8 {
506 return s.constInt64(t, c)
507 }
508 if int64(int32(c)) != c {
509 s.Fatalf("integer constant too big %d", c)
510 }
511 return s.constInt32(t, int32(c))
Michael Matloob81ccf502015-05-30 01:03:06 -0400512}
513
Keith Randall4fffd4562016-02-29 13:31:48 -0800514func (s *state) stmts(a Nodes) {
515 for _, x := range a.Slice() {
516 s.stmt(x)
517 }
518}
519
Keith Randalld2fd43a2015-04-15 15:51:25 -0700520// ssaStmtList converts the statement n to SSA and adds it to s.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800521func (s *state) stmtList(l Nodes) {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800522 for _, n := range l.Slice() {
523 s.stmt(n)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700524 }
525}
526
527// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700528func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400529 s.pushLine(n.Lineno)
530 defer s.popLine()
531
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700532 // If s.curBlock is nil, then we're about to generate dead code.
533 // We can't just short-circuit here, though,
534 // because we check labels and gotos as part of SSA generation.
535 // Provide a block for the dead code so that we don't have
536 // to add special cases everywhere else.
537 if s.curBlock == nil {
538 dead := s.f.NewBlock(ssa.BlockPlain)
539 s.startBlock(dead)
540 }
541
Keith Randalld2fd43a2015-04-15 15:51:25 -0700542 s.stmtList(n.Ninit)
543 switch n.Op {
544
545 case OBLOCK:
546 s.stmtList(n.List)
547
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600548 // No-ops
Todd Neal67e43c12015-08-28 21:19:40 -0500549 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600550
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600551 // Expression statements
552 case OCALLFUNC, OCALLMETH, OCALLINTER:
Keith Randalld24768e2015-09-09 23:56:59 -0700553 s.call(n, callNormal)
Keith Randallfb54e032016-02-24 16:19:20 -0800554 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
555 (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
Keith Randall6a8a9da2016-02-27 17:49:31 -0800556 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 -0800557 m := s.mem()
558 b := s.endBlock()
559 b.Kind = ssa.BlockExit
Keith Randall56e0ecc2016-03-15 20:45:50 -0700560 b.SetControl(m)
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800561 // TODO: never rewrite OPANIC to OCALLFUNC in the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000562 // first place. Need to wait until all backends
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800563 // go through SSA.
564 }
Keith Randalld24768e2015-09-09 23:56:59 -0700565 case ODEFER:
566 s.call(n.Left, callDefer)
567 case OPROC:
568 s.call(n.Left, callGo)
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600569
Keith Randall269baa92015-09-17 10:31:16 -0700570 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800571 res, resok := s.dottype(n.Rlist.First(), true)
Keith Randalld4663e12016-03-21 10:22:03 -0700572 s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno, 0)
573 s.assign(n.List.Second(), resok, false, false, n.Lineno, 0)
Keith Randall269baa92015-09-17 10:31:16 -0700574 return
575
Keith Randalld2fd43a2015-04-15 15:51:25 -0700576 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100577 if n.Left.Class&PHEAP == 0 {
578 return
579 }
580 if compiling_runtime != 0 {
Keith Randall0ec72b62015-09-08 15:42:53 -0700581 Fatalf("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100582 }
583
584 // TODO: the old pass hides the details of PHEAP
585 // variables behind ONAME nodes. Figure out if it's better
586 // to rewrite the tree and make the heapaddr construct explicit
587 // or to keep this detail hidden behind the scenes.
588 palloc := prealloc[n.Left]
589 if palloc == nil {
590 palloc = callnew(n.Left.Type)
591 prealloc[n.Left] = palloc
592 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700593 r := s.expr(palloc)
Keith Randalld4663e12016-03-21 10:22:03 -0700594 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno, 0)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700595
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700596 case OLABEL:
597 sym := n.Left.Sym
598
599 if isblanksym(sym) {
Keith Randall7e4c06d2015-07-12 11:52:09 -0700600 // Empty identifier is valid but useless.
601 // See issues 11589, 11593.
602 return
603 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700604
605 lab := s.label(sym)
606
607 // Associate label with its control flow node, if any
608 if ctl := n.Name.Defn; ctl != nil {
609 switch ctl.Op {
610 case OFOR, OSWITCH, OSELECT:
611 s.labeledNodes[ctl] = lab
612 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700613 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700614
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700615 if !lab.defined() {
616 lab.defNode = n
617 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800618 s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700619 lab.reported = true
Keith Randalld2fd43a2015-04-15 15:51:25 -0700620 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700621 // The label might already have a target block via a goto.
622 if lab.target == nil {
623 lab.target = s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700624 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700625
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700626 // go to that label (we pretend "label:" is preceded by "goto label")
627 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500628 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700629 s.startBlock(lab.target)
630
631 case OGOTO:
632 sym := n.Left.Sym
633
634 lab := s.label(sym)
635 if lab.target == nil {
636 lab.target = s.f.NewBlock(ssa.BlockPlain)
637 }
638 if !lab.used() {
639 lab.useNode = n
640 }
641
642 if lab.defined() {
643 s.checkgoto(n, lab.defNode)
644 } else {
645 s.fwdGotos = append(s.fwdGotos, n)
646 }
647
648 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500649 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700650
Keith Randall290d8fc2015-06-10 15:03:06 -0700651 case OAS, OASWB:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700652 // Check whether we can generate static data rather than code.
653 // If so, ignore n and defer data generation until codegen.
654 // Failure to do this causes writes to readonly symbols.
655 if gen_as_init(n, true) {
656 var data []*Node
657 if s.f.StaticData != nil {
658 data = s.f.StaticData.([]*Node)
659 }
660 s.f.StaticData = append(data, n)
661 return
662 }
Keith Randall5ba31942016-01-25 17:06:54 -0800663
664 var t *Type
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700665 if n.Right != nil {
Keith Randall5ba31942016-01-25 17:06:54 -0800666 t = n.Right.Type
667 } else {
668 t = n.Left.Type
669 }
670
671 // Evaluate RHS.
672 rhs := n.Right
673 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
674 // All literals with nonzero fields have already been
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000675 // rewritten during walk. Any that remain are just T{}
676 // or equivalents. Use the zero value.
Keith Randall5ba31942016-01-25 17:06:54 -0800677 if !iszero(rhs) {
678 Fatalf("literal with nonzero value in SSA: %v", rhs)
679 }
680 rhs = nil
681 }
682 var r *ssa.Value
683 needwb := n.Op == OASWB && rhs != nil
684 deref := !canSSAType(t)
685 if deref {
686 if rhs == nil {
687 r = nil // Signal assign to use OpZero.
Keith Randalld3886902015-09-18 22:12:38 -0700688 } else {
Keith Randall5ba31942016-01-25 17:06:54 -0800689 r = s.addr(rhs, false)
690 }
691 } else {
692 if rhs == nil {
693 r = s.zeroVal(t)
694 } else {
695 r = s.expr(rhs)
Keith Randalld3886902015-09-18 22:12:38 -0700696 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700697 }
Keith Randall5ba31942016-01-25 17:06:54 -0800698 if rhs != nil && rhs.Op == OAPPEND {
Keith Randall9d22c102015-09-11 11:02:57 -0700699 // Yuck! The frontend gets rid of the write barrier, but we need it!
700 // At least, we need it in the case where growslice is called.
701 // TODO: Do the write barrier on just the growslice branch.
702 // TODO: just add a ptr graying to the end of growslice?
703 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
704 // They get similar wb-removal treatment in walk.go:OAS.
Keith Randall5ba31942016-01-25 17:06:54 -0800705 needwb = true
Keith Randall9d22c102015-09-11 11:02:57 -0700706 }
Keith Randall5ba31942016-01-25 17:06:54 -0800707
Keith Randalld4663e12016-03-21 10:22:03 -0700708 var skip skipMask
709 if rhs != nil && (rhs.Op == OSLICE || rhs.Op == OSLICE3 || rhs.Op == OSLICESTR) && samesafeexpr(rhs.Left, n.Left) {
710 // We're assigning a slicing operation back to its source.
711 // Don't write back fields we aren't changing. See issue #14855.
712 i := rhs.Right.Left
713 var j, k *Node
714 if rhs.Op == OSLICE3 {
715 j = rhs.Right.Right.Left
716 k = rhs.Right.Right.Right
717 } else {
718 j = rhs.Right.Right
719 }
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -0700720 if i != nil && (i.Op == OLITERAL && i.Val().Ctype() == CTINT && i.Int64() == 0) {
Keith Randalld4663e12016-03-21 10:22:03 -0700721 // [0:...] is the same as [:...]
722 i = nil
723 }
724 // TODO: detect defaults for len/cap also.
725 // Currently doesn't really work because (*p)[:len(*p)] appears here as:
726 // tmp = len(*p)
727 // (*p)[:tmp]
728 //if j != nil && (j.Op == OLEN && samesafeexpr(j.Left, n.Left)) {
729 // j = nil
730 //}
731 //if k != nil && (k.Op == OCAP && samesafeexpr(k.Left, n.Left)) {
732 // k = nil
733 //}
734 if i == nil {
735 skip |= skipPtr
736 if j == nil {
737 skip |= skipLen
738 }
739 if k == nil {
740 skip |= skipCap
741 }
742 }
743 }
744
745 s.assign(n.Left, r, needwb, deref, n.Lineno, skip)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100746
Keith Randalld2fd43a2015-04-15 15:51:25 -0700747 case OIF:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700748 bThen := s.f.NewBlock(ssa.BlockPlain)
749 bEnd := s.f.NewBlock(ssa.BlockPlain)
750 var bElse *ssa.Block
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800751 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700752 bElse = s.f.NewBlock(ssa.BlockPlain)
Keith Randall99187312015-11-02 16:56:53 -0800753 s.condBranch(n.Left, bThen, bElse, n.Likely)
754 } else {
755 s.condBranch(n.Left, bThen, bEnd, n.Likely)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700756 }
757
758 s.startBlock(bThen)
Keith Randall9d854fd2016-03-01 12:50:17 -0800759 s.stmts(n.Nbody)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700760 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500761 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700762 }
763
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800764 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700765 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700766 s.stmtList(n.Rlist)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700767 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500768 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700769 }
770 }
771 s.startBlock(bEnd)
772
773 case ORETURN:
774 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800775 s.exit()
Keith Randall8a1f6212015-09-08 21:28:44 -0700776 case ORETJMP:
777 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800778 b := s.exit()
779 b.Kind = ssa.BlockRetJmp // override BlockRet
Keith Randall8a1f6212015-09-08 21:28:44 -0700780 b.Aux = n.Left.Sym
Keith Randalld2fd43a2015-04-15 15:51:25 -0700781
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700782 case OCONTINUE, OBREAK:
783 var op string
784 var to *ssa.Block
785 switch n.Op {
786 case OCONTINUE:
787 op = "continue"
788 to = s.continueTo
789 case OBREAK:
790 op = "break"
791 to = s.breakTo
792 }
793 if n.Left == nil {
794 // plain break/continue
795 if to == nil {
796 s.Error("%s is not in a loop", op)
797 return
798 }
799 // nothing to do; "to" is already the correct target
800 } else {
801 // labeled break/continue; look up the target
802 sym := n.Left.Sym
803 lab := s.label(sym)
804 if !lab.used() {
805 lab.useNode = n.Left
806 }
807 if !lab.defined() {
808 s.Error("%s label not defined: %v", op, sym)
809 lab.reported = true
810 return
811 }
812 switch n.Op {
813 case OCONTINUE:
814 to = lab.continueTarget
815 case OBREAK:
816 to = lab.breakTarget
817 }
818 if to == nil {
819 // Valid label but not usable with a break/continue here, e.g.:
820 // for {
821 // continue abc
822 // }
823 // abc:
824 // for {}
825 s.Error("invalid %s label %v", op, sym)
826 lab.reported = true
827 return
828 }
829 }
830
831 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500832 b.AddEdgeTo(to)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700833
Keith Randalld2fd43a2015-04-15 15:51:25 -0700834 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700835 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700836 bCond := s.f.NewBlock(ssa.BlockPlain)
837 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700838 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700839 bEnd := s.f.NewBlock(ssa.BlockPlain)
840
841 // first, jump to condition test
842 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500843 b.AddEdgeTo(bCond)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700844
845 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700846 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700847 if n.Left != nil {
Keith Randall99187312015-11-02 16:56:53 -0800848 s.condBranch(n.Left, bBody, bEnd, 1)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700849 } else {
Keith Randall99187312015-11-02 16:56:53 -0800850 b := s.endBlock()
851 b.Kind = ssa.BlockPlain
852 b.AddEdgeTo(bBody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700853 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700854
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700855 // set up for continue/break in body
856 prevContinue := s.continueTo
857 prevBreak := s.breakTo
858 s.continueTo = bIncr
859 s.breakTo = bEnd
860 lab := s.labeledNodes[n]
861 if lab != nil {
862 // labeled for loop
863 lab.continueTarget = bIncr
864 lab.breakTarget = bEnd
865 }
866
Keith Randalld2fd43a2015-04-15 15:51:25 -0700867 // generate body
868 s.startBlock(bBody)
Keith Randall9d854fd2016-03-01 12:50:17 -0800869 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700870
871 // tear down continue/break
872 s.continueTo = prevContinue
873 s.breakTo = prevBreak
874 if lab != nil {
875 lab.continueTarget = nil
876 lab.breakTarget = nil
877 }
878
879 // done with body, goto incr
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700880 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500881 b.AddEdgeTo(bIncr)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700882 }
883
884 // generate incr
885 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700886 if n.Right != nil {
887 s.stmt(n.Right)
888 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700889 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500890 b.AddEdgeTo(bCond)
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700891 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700892 s.startBlock(bEnd)
893
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700894 case OSWITCH, OSELECT:
895 // These have been mostly rewritten by the front end into their Nbody fields.
896 // Our main task is to correctly hook up any break statements.
897 bEnd := s.f.NewBlock(ssa.BlockPlain)
898
899 prevBreak := s.breakTo
900 s.breakTo = bEnd
901 lab := s.labeledNodes[n]
902 if lab != nil {
903 // labeled
904 lab.breakTarget = bEnd
905 }
906
907 // generate body code
Keith Randall9d854fd2016-03-01 12:50:17 -0800908 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700909
910 s.breakTo = prevBreak
911 if lab != nil {
912 lab.breakTarget = nil
913 }
914
Keith Randalleb0cff92016-02-09 12:28:02 -0800915 // OSWITCH never falls through (s.curBlock == nil here).
916 // OSELECT does not fall through if we're calling selectgo.
917 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
918 // In those latter cases, go to the code after the select.
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700919 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500920 b.AddEdgeTo(bEnd)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700921 }
922 s.startBlock(bEnd)
923
Keith Randalld2fd43a2015-04-15 15:51:25 -0700924 case OVARKILL:
Keith Randalld2107fc2015-08-24 02:16:19 -0700925 // Insert a varkill op to record that a variable is no longer live.
926 // We only care about liveness info at call sites, so putting the
927 // varkill in the store chain is enough to keep it correctly ordered
928 // with respect to call ops.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800929 if !s.canSSA(n.Left) {
Keith Randalld29e92b2015-09-19 12:01:39 -0700930 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
931 }
Keith Randall9569b952015-08-28 22:51:01 -0700932
Keith Randall23d58102016-01-19 09:59:21 -0800933 case OVARLIVE:
934 // Insert a varlive op to record that a variable is still live.
935 if !n.Left.Addrtaken {
936 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
937 }
938 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
939
Keith Randall46ffb022015-09-12 14:06:44 -0700940 case OCHECKNIL:
941 p := s.expr(n.Left)
942 s.nilCheck(p)
943
Keith Randalld2fd43a2015-04-15 15:51:25 -0700944 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700945 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700946 }
947}
948
Keith Randall6a8a9da2016-02-27 17:49:31 -0800949// exit processes any code that needs to be generated just before returning.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000950// It returns a BlockRet block that ends the control flow. Its control value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800951// will be set to the final memory state.
952func (s *state) exit() *ssa.Block {
Keith Randallddc6b642016-03-09 19:27:57 -0800953 if hasdefer {
954 s.rtcall(Deferreturn, true, nil)
955 }
956
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000957 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
Keith Randall6a8a9da2016-02-27 17:49:31 -0800958 // variables back to the stack.
959 s.stmts(s.exitCode)
960
961 // Store SSAable PPARAMOUT variables back to stack locations.
962 for _, n := range s.returns {
963 aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
964 addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
965 val := s.variable(n, n.Type)
966 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
967 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
968 // TODO: if val is ever spilled, we'd like to use the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000969 // PPARAMOUT slot for spilling it. That won't happen
Keith Randall6a8a9da2016-02-27 17:49:31 -0800970 // currently.
971 }
972
973 // Do actual return.
974 m := s.mem()
975 b := s.endBlock()
976 b.Kind = ssa.BlockRet
Keith Randall56e0ecc2016-03-15 20:45:50 -0700977 b.SetControl(m)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800978 return b
979}
980
Keith Randall67fdb0d2015-07-19 15:48:20 -0700981type opAndType struct {
Keith Randall4304fbc2015-11-16 13:20:16 -0800982 op Op
983 etype EType
Keith Randall67fdb0d2015-07-19 15:48:20 -0700984}
985
986var opToSSA = map[opAndType]ssa.Op{
David Chase997a9f32015-08-12 16:38:11 -0400987 opAndType{OADD, TINT8}: ssa.OpAdd8,
988 opAndType{OADD, TUINT8}: ssa.OpAdd8,
989 opAndType{OADD, TINT16}: ssa.OpAdd16,
990 opAndType{OADD, TUINT16}: ssa.OpAdd16,
991 opAndType{OADD, TINT32}: ssa.OpAdd32,
992 opAndType{OADD, TUINT32}: ssa.OpAdd32,
993 opAndType{OADD, TPTR32}: ssa.OpAdd32,
994 opAndType{OADD, TINT64}: ssa.OpAdd64,
995 opAndType{OADD, TUINT64}: ssa.OpAdd64,
996 opAndType{OADD, TPTR64}: ssa.OpAdd64,
997 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
998 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700999
David Chase997a9f32015-08-12 16:38:11 -04001000 opAndType{OSUB, TINT8}: ssa.OpSub8,
1001 opAndType{OSUB, TUINT8}: ssa.OpSub8,
1002 opAndType{OSUB, TINT16}: ssa.OpSub16,
1003 opAndType{OSUB, TUINT16}: ssa.OpSub16,
1004 opAndType{OSUB, TINT32}: ssa.OpSub32,
1005 opAndType{OSUB, TUINT32}: ssa.OpSub32,
1006 opAndType{OSUB, TINT64}: ssa.OpSub64,
1007 opAndType{OSUB, TUINT64}: ssa.OpSub64,
1008 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
1009 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001010
Josh Bleecher Snydere61e7c92015-07-22 19:19:40 -07001011 opAndType{ONOT, TBOOL}: ssa.OpNot,
1012
David Chase3a9d0ac2015-08-28 14:24:10 -04001013 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
1014 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
1015 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
1016 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
1017 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
1018 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
1019 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
1020 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
1021 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
1022 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001023
Keith Randall4b803152015-07-29 17:07:09 -07001024 opAndType{OCOM, TINT8}: ssa.OpCom8,
1025 opAndType{OCOM, TUINT8}: ssa.OpCom8,
1026 opAndType{OCOM, TINT16}: ssa.OpCom16,
1027 opAndType{OCOM, TUINT16}: ssa.OpCom16,
1028 opAndType{OCOM, TINT32}: ssa.OpCom32,
1029 opAndType{OCOM, TUINT32}: ssa.OpCom32,
1030 opAndType{OCOM, TINT64}: ssa.OpCom64,
1031 opAndType{OCOM, TUINT64}: ssa.OpCom64,
1032
Josh Bleecher Snyderfa5fe192015-09-06 19:24:59 -07001033 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
1034 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
1035 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
1036 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
1037
David Chase997a9f32015-08-12 16:38:11 -04001038 opAndType{OMUL, TINT8}: ssa.OpMul8,
1039 opAndType{OMUL, TUINT8}: ssa.OpMul8,
1040 opAndType{OMUL, TINT16}: ssa.OpMul16,
1041 opAndType{OMUL, TUINT16}: ssa.OpMul16,
1042 opAndType{OMUL, TINT32}: ssa.OpMul32,
1043 opAndType{OMUL, TUINT32}: ssa.OpMul32,
1044 opAndType{OMUL, TINT64}: ssa.OpMul64,
1045 opAndType{OMUL, TUINT64}: ssa.OpMul64,
1046 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
1047 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
1048
1049 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
1050 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
Keith Randallbe1eb572015-07-22 13:46:15 -07001051
Todd Neal67cbd5b2015-08-18 19:14:47 -05001052 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
1053 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
1054 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
1055 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
1056 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
1057 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
1058
Todd Neala45f2d82015-08-17 17:46:06 -05001059 opAndType{ODIV, TINT8}: ssa.OpDiv8,
1060 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
1061 opAndType{ODIV, TINT16}: ssa.OpDiv16,
1062 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
1063 opAndType{ODIV, TINT32}: ssa.OpDiv32,
1064 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
1065 opAndType{ODIV, TINT64}: ssa.OpDiv64,
1066 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
1067
Todd Neal57d9e7e2015-08-18 19:51:44 -05001068 opAndType{OMOD, TINT8}: ssa.OpMod8,
1069 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1070 opAndType{OMOD, TINT16}: ssa.OpMod16,
1071 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1072 opAndType{OMOD, TINT32}: ssa.OpMod32,
1073 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1074 opAndType{OMOD, TINT64}: ssa.OpMod64,
1075 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1076
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001077 opAndType{OAND, TINT8}: ssa.OpAnd8,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001078 opAndType{OAND, TUINT8}: ssa.OpAnd8,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001079 opAndType{OAND, TINT16}: ssa.OpAnd16,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001080 opAndType{OAND, TUINT16}: ssa.OpAnd16,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001081 opAndType{OAND, TINT32}: ssa.OpAnd32,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001082 opAndType{OAND, TUINT32}: ssa.OpAnd32,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001083 opAndType{OAND, TINT64}: ssa.OpAnd64,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001084 opAndType{OAND, TUINT64}: ssa.OpAnd64,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001085
Alexandru Moșoi74024162015-07-29 17:52:25 +02001086 opAndType{OOR, TINT8}: ssa.OpOr8,
1087 opAndType{OOR, TUINT8}: ssa.OpOr8,
1088 opAndType{OOR, TINT16}: ssa.OpOr16,
1089 opAndType{OOR, TUINT16}: ssa.OpOr16,
1090 opAndType{OOR, TINT32}: ssa.OpOr32,
1091 opAndType{OOR, TUINT32}: ssa.OpOr32,
1092 opAndType{OOR, TINT64}: ssa.OpOr64,
1093 opAndType{OOR, TUINT64}: ssa.OpOr64,
1094
Alexandru Moșoi6d9362a12015-07-30 12:33:36 +02001095 opAndType{OXOR, TINT8}: ssa.OpXor8,
1096 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1097 opAndType{OXOR, TINT16}: ssa.OpXor16,
1098 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1099 opAndType{OXOR, TINT32}: ssa.OpXor32,
1100 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1101 opAndType{OXOR, TINT64}: ssa.OpXor64,
1102 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1103
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001104 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1105 opAndType{OEQ, TINT8}: ssa.OpEq8,
1106 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1107 opAndType{OEQ, TINT16}: ssa.OpEq16,
1108 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1109 opAndType{OEQ, TINT32}: ssa.OpEq32,
1110 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1111 opAndType{OEQ, TINT64}: ssa.OpEq64,
1112 opAndType{OEQ, TUINT64}: ssa.OpEq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001113 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1114 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001115 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1116 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1117 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001118 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001119 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1120 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001121 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1122 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001123
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001124 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1125 opAndType{ONE, TINT8}: ssa.OpNeq8,
1126 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1127 opAndType{ONE, TINT16}: ssa.OpNeq16,
1128 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1129 opAndType{ONE, TINT32}: ssa.OpNeq32,
1130 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1131 opAndType{ONE, TINT64}: ssa.OpNeq64,
1132 opAndType{ONE, TUINT64}: ssa.OpNeq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001133 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1134 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001135 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1136 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1137 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001138 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001139 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1140 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001141 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1142 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001143
David Chase8e601b22015-08-18 14:39:26 -04001144 opAndType{OLT, TINT8}: ssa.OpLess8,
1145 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1146 opAndType{OLT, TINT16}: ssa.OpLess16,
1147 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1148 opAndType{OLT, TINT32}: ssa.OpLess32,
1149 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1150 opAndType{OLT, TINT64}: ssa.OpLess64,
1151 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1152 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1153 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001154
David Chase8e601b22015-08-18 14:39:26 -04001155 opAndType{OGT, TINT8}: ssa.OpGreater8,
1156 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1157 opAndType{OGT, TINT16}: ssa.OpGreater16,
1158 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1159 opAndType{OGT, TINT32}: ssa.OpGreater32,
1160 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1161 opAndType{OGT, TINT64}: ssa.OpGreater64,
1162 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1163 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1164 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001165
David Chase8e601b22015-08-18 14:39:26 -04001166 opAndType{OLE, TINT8}: ssa.OpLeq8,
1167 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1168 opAndType{OLE, TINT16}: ssa.OpLeq16,
1169 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1170 opAndType{OLE, TINT32}: ssa.OpLeq32,
1171 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1172 opAndType{OLE, TINT64}: ssa.OpLeq64,
1173 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1174 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1175 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001176
David Chase8e601b22015-08-18 14:39:26 -04001177 opAndType{OGE, TINT8}: ssa.OpGeq8,
1178 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1179 opAndType{OGE, TINT16}: ssa.OpGeq16,
1180 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1181 opAndType{OGE, TINT32}: ssa.OpGeq32,
1182 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1183 opAndType{OGE, TINT64}: ssa.OpGeq64,
1184 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1185 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1186 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
David Chase40aba8c2015-08-05 22:11:14 -04001187
1188 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1189 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1190 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1191 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
Keith Randalla329e212015-09-12 13:26:57 -07001192
1193 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001194}
1195
Keith Randall4304fbc2015-11-16 13:20:16 -08001196func (s *state) concreteEtype(t *Type) EType {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001197 e := t.Etype
1198 switch e {
1199 default:
1200 return e
Keith Randall67fdb0d2015-07-19 15:48:20 -07001201 case TINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001202 if s.config.IntSize == 8 {
1203 return TINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001204 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001205 return TINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001206 case TUINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001207 if s.config.IntSize == 8 {
1208 return TUINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001209 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001210 return TUINT32
1211 case TUINTPTR:
1212 if s.config.PtrSize == 8 {
1213 return TUINT64
1214 }
1215 return TUINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001216 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001217}
1218
Keith Randall4304fbc2015-11-16 13:20:16 -08001219func (s *state) ssaOp(op Op, t *Type) ssa.Op {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001220 etype := s.concreteEtype(t)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001221 x, ok := opToSSA[opAndType{op, etype}]
1222 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001223 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
Keith Randall67fdb0d2015-07-19 15:48:20 -07001224 }
1225 return x
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001226}
1227
David Chase3a9d0ac2015-08-28 14:24:10 -04001228func floatForComplex(t *Type) *Type {
1229 if t.Size() == 8 {
1230 return Types[TFLOAT32]
1231 } else {
1232 return Types[TFLOAT64]
1233 }
1234}
1235
Keith Randall4b803152015-07-29 17:07:09 -07001236type opAndTwoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001237 op Op
1238 etype1 EType
1239 etype2 EType
Keith Randall4b803152015-07-29 17:07:09 -07001240}
1241
David Chased052bbd2015-09-01 17:09:00 -04001242type twoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001243 etype1 EType
1244 etype2 EType
David Chased052bbd2015-09-01 17:09:00 -04001245}
1246
1247type twoOpsAndType struct {
1248 op1 ssa.Op
1249 op2 ssa.Op
Keith Randall4304fbc2015-11-16 13:20:16 -08001250 intermediateType EType
David Chased052bbd2015-09-01 17:09:00 -04001251}
1252
1253var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1254
1255 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1256 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1257 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1258 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1259
1260 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1261 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1262 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1263 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1264
1265 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1266 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1267 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1268 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1269
1270 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1271 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1272 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1273 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1274 // unsigned
1275 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1276 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1277 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1278 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1279
1280 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1281 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1282 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1283 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1284
1285 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1286 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1287 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1288 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1289
1290 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1291 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1292 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1293 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1294
1295 // float
1296 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1297 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1298 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1299 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1300}
1301
Keith Randall4b803152015-07-29 17:07:09 -07001302var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1303 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1304 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1305 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1306 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1307 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1308 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1309 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1310 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1311
1312 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1313 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1314 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1315 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1316 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1317 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1318 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1319 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1320
1321 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1322 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1323 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1324 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1325 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1326 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1327 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1328 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1329
1330 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1331 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1332 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1333 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1334 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1335 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1336 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1337 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1338
1339 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1340 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1341 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1342 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1343 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1344 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1345 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1346 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1347
1348 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1349 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1350 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1351 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1352 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1353 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1354 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1355 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1356
1357 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1358 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1359 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1360 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1361 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1362 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1363 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1364 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1365
1366 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1367 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1368 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1369 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1370 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1371 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1372 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1373 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1374}
1375
Keith Randall4304fbc2015-11-16 13:20:16 -08001376func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
Keith Randall4b803152015-07-29 17:07:09 -07001377 etype1 := s.concreteEtype(t)
1378 etype2 := s.concreteEtype(u)
1379 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1380 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001381 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
Keith Randall4b803152015-07-29 17:07:09 -07001382 }
1383 return x
1384}
1385
Keith Randall4304fbc2015-11-16 13:20:16 -08001386func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
David Chase40aba8c2015-08-05 22:11:14 -04001387 etype1 := s.concreteEtype(t)
1388 x, ok := opToSSA[opAndType{op, etype1}]
1389 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001390 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
David Chase40aba8c2015-08-05 22:11:14 -04001391 }
1392 return x
1393}
1394
Keith Randalld2fd43a2015-04-15 15:51:25 -07001395// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -07001396func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -04001397 s.pushLine(n.Lineno)
1398 defer s.popLine()
1399
Keith Randall06f32922015-07-11 11:39:12 -07001400 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001401 switch n.Op {
Todd Nealdef7c652015-09-07 19:07:02 -05001402 case OCFUNC:
Todd Neald076ef72015-10-15 20:25:32 -05001403 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
Todd Nealdef7c652015-09-07 19:07:02 -05001404 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
David Chase956f3192015-09-11 16:40:05 -04001405 case OPARAM:
David Chase57670ad2015-10-09 16:48:30 -04001406 addr := s.addr(n, false)
David Chase32ffbf72015-10-08 17:14:12 -04001407 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001408 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07001409 if n.Class == PFUNC {
1410 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -07001411 sym := funcsym(n.Sym)
1412 aux := &ssa.ExternSymbol{n.Type, sym}
1413 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -07001414 }
Keith Randall6a8a9da2016-02-27 17:49:31 -08001415 if s.canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -07001416 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -07001417 }
David Chase57670ad2015-10-09 16:48:30 -04001418 addr := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001419 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
David Chase956f3192015-09-11 16:40:05 -04001420 case OCLOSUREVAR:
David Chase57670ad2015-10-09 16:48:30 -04001421 addr := s.addr(n, false)
David Chase956f3192015-09-11 16:40:05 -04001422 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001423 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -07001424 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -07001425 case CTINT:
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001426 i := n.Int64()
Keith Randall9cb332e2015-07-28 14:19:20 -07001427 switch n.Type.Size() {
1428 case 1:
1429 return s.constInt8(n.Type, int8(i))
1430 case 2:
1431 return s.constInt16(n.Type, int16(i))
1432 case 4:
1433 return s.constInt32(n.Type, int32(i))
1434 case 8:
1435 return s.constInt64(n.Type, i)
1436 default:
1437 s.Fatalf("bad integer size %d", n.Type.Size())
1438 return nil
1439 }
1440 case CTSTR:
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001441 if n.Val().U == "" {
1442 return s.constEmptyString(n.Type)
1443 }
Keith Randall9cb332e2015-07-28 14:19:20 -07001444 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1445 case CTBOOL:
Keith Randallb5c5efd2016-01-14 16:02:23 -08001446 v := s.constBool(n.Val().U.(bool))
1447 // For some reason the frontend gets the line numbers of
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001448 // CTBOOL literals totally wrong. Fix it here by grabbing
Keith Randallb5c5efd2016-01-14 16:02:23 -08001449 // the line number of the enclosing AST node.
1450 if len(s.line) >= 2 {
1451 v.Line = s.line[len(s.line)-2]
1452 }
1453 return v
Brad Fitzpatrick337b7e72015-07-13 17:30:42 -06001454 case CTNIL:
Keith Randall9f954db2015-08-18 10:26:28 -07001455 t := n.Type
1456 switch {
1457 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001458 return s.constSlice(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001459 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001460 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001461 default:
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001462 return s.constNil(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001463 }
David Chase997a9f32015-08-12 16:38:11 -04001464 case CTFLT:
1465 f := n.Val().U.(*Mpflt)
1466 switch n.Type.Size() {
1467 case 4:
Matthew Dempskyd3253872016-03-20 13:55:42 -07001468 return s.constFloat32(n.Type, f.Float32())
David Chase997a9f32015-08-12 16:38:11 -04001469 case 8:
Matthew Dempskyd3253872016-03-20 13:55:42 -07001470 return s.constFloat64(n.Type, f.Float64())
David Chase997a9f32015-08-12 16:38:11 -04001471 default:
1472 s.Fatalf("bad float size %d", n.Type.Size())
1473 return nil
1474 }
David Chase52578582015-08-28 14:24:10 -04001475 case CTCPLX:
1476 c := n.Val().U.(*Mpcplx)
1477 r := &c.Real
1478 i := &c.Imag
1479 switch n.Type.Size() {
1480 case 8:
1481 {
1482 pt := Types[TFLOAT32]
1483 return s.newValue2(ssa.OpComplexMake, n.Type,
Matthew Dempskyd3253872016-03-20 13:55:42 -07001484 s.constFloat32(pt, r.Float32()),
1485 s.constFloat32(pt, i.Float32()))
David Chase52578582015-08-28 14:24:10 -04001486 }
1487 case 16:
1488 {
1489 pt := Types[TFLOAT64]
1490 return s.newValue2(ssa.OpComplexMake, n.Type,
Matthew Dempskyd3253872016-03-20 13:55:42 -07001491 s.constFloat64(pt, r.Float64()),
1492 s.constFloat64(pt, i.Float64()))
David Chase52578582015-08-28 14:24:10 -04001493 }
1494 default:
1495 s.Fatalf("bad float size %d", n.Type.Size())
1496 return nil
1497 }
David Chase997a9f32015-08-12 16:38:11 -04001498
Keith Randalld2fd43a2015-04-15 15:51:25 -07001499 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001500 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001501 return nil
1502 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001503 case OCONVNOP:
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001504 to := n.Type
1505 from := n.Left.Type
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001506
1507 // Assume everything will work out, so set up our return value.
1508 // Anything interesting that happens from here is a fatal.
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001509 x := s.expr(n.Left)
David Chasee99dd522015-10-19 11:36:07 -04001510
1511 // Special case for not confusing GC and liveness.
1512 // We don't want pointers accidentally classified
1513 // as not-pointers or vice-versa because of copy
1514 // elision.
Matthew Dempsky788f1122016-03-28 10:55:44 -07001515 if to.IsPtrShaped() != from.IsPtrShaped() {
Keith Randall7807bda2015-11-10 15:35:36 -08001516 return s.newValue2(ssa.OpConvert, to, x, s.mem())
David Chasee99dd522015-10-19 11:36:07 -04001517 }
1518
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001519 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1520
Todd Nealdef7c652015-09-07 19:07:02 -05001521 // CONVNOP closure
Matthew Dempsky788f1122016-03-28 10:55:44 -07001522 if to.Etype == TFUNC && from.IsPtrShaped() {
Todd Nealdef7c652015-09-07 19:07:02 -05001523 return v
1524 }
1525
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001526 // named <--> unnamed type or typed <--> untyped const
1527 if from.Etype == to.Etype {
1528 return v
1529 }
David Chasee99dd522015-10-19 11:36:07 -04001530
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001531 // unsafe.Pointer <--> *T
1532 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1533 return v
1534 }
1535
1536 dowidth(from)
1537 dowidth(to)
1538 if from.Width != to.Width {
1539 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1540 return nil
1541 }
1542 if etypesign(from.Etype) != etypesign(to.Etype) {
Keith Randall4304fbc2015-11-16 13:20:16 -08001543 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001544 return nil
1545 }
1546
Ian Lance Taylor88e18032016-03-01 15:17:34 -08001547 if instrumenting {
David Chase57670ad2015-10-09 16:48:30 -04001548 // These appear to be fine, but they fail the
1549 // integer constraint below, so okay them here.
1550 // Sample non-integer conversion: map[string]string -> *uint8
1551 return v
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001552 }
1553
1554 if etypesign(from.Etype) == 0 {
1555 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1556 return nil
1557 }
1558
1559 // integer, same width, same sign
1560 return v
1561
Michael Matloob73054f52015-06-14 11:38:46 -07001562 case OCONV:
1563 x := s.expr(n.Left)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001564 ft := n.Left.Type // from type
1565 tt := n.Type // to type
1566 if ft.IsInteger() && tt.IsInteger() {
1567 var op ssa.Op
1568 if tt.Size() == ft.Size() {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001569 op = ssa.OpCopy
Keith Randall2a5e6c42015-07-23 14:35:02 -07001570 } else if tt.Size() < ft.Size() {
1571 // truncation
1572 switch 10*ft.Size() + tt.Size() {
1573 case 21:
1574 op = ssa.OpTrunc16to8
1575 case 41:
1576 op = ssa.OpTrunc32to8
1577 case 42:
1578 op = ssa.OpTrunc32to16
1579 case 81:
1580 op = ssa.OpTrunc64to8
1581 case 82:
1582 op = ssa.OpTrunc64to16
1583 case 84:
1584 op = ssa.OpTrunc64to32
1585 default:
1586 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1587 }
1588 } else if ft.IsSigned() {
1589 // sign extension
1590 switch 10*ft.Size() + tt.Size() {
1591 case 12:
1592 op = ssa.OpSignExt8to16
1593 case 14:
1594 op = ssa.OpSignExt8to32
1595 case 18:
1596 op = ssa.OpSignExt8to64
1597 case 24:
1598 op = ssa.OpSignExt16to32
1599 case 28:
1600 op = ssa.OpSignExt16to64
1601 case 48:
1602 op = ssa.OpSignExt32to64
1603 default:
1604 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1605 }
1606 } else {
1607 // zero extension
1608 switch 10*ft.Size() + tt.Size() {
1609 case 12:
1610 op = ssa.OpZeroExt8to16
1611 case 14:
1612 op = ssa.OpZeroExt8to32
1613 case 18:
1614 op = ssa.OpZeroExt8to64
1615 case 24:
1616 op = ssa.OpZeroExt16to32
1617 case 28:
1618 op = ssa.OpZeroExt16to64
1619 case 48:
1620 op = ssa.OpZeroExt32to64
1621 default:
1622 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1623 }
1624 }
1625 return s.newValue1(op, n.Type, x)
1626 }
David Chase42825882015-08-20 15:14:20 -04001627
David Chased052bbd2015-09-01 17:09:00 -04001628 if ft.IsFloat() || tt.IsFloat() {
1629 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1630 if !ok {
1631 s.Fatalf("weird float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001632 }
David Chased052bbd2015-09-01 17:09:00 -04001633 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1634
1635 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1636 // normal case, not tripping over unsigned 64
1637 if op1 == ssa.OpCopy {
1638 if op2 == ssa.OpCopy {
1639 return x
1640 }
1641 return s.newValue1(op2, n.Type, x)
1642 }
1643 if op2 == ssa.OpCopy {
1644 return s.newValue1(op1, n.Type, x)
1645 }
1646 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1647 }
1648 // Tricky 64-bit unsigned cases.
1649 if ft.IsInteger() {
1650 // therefore tt is float32 or float64, and ft is also unsigned
David Chase42825882015-08-20 15:14:20 -04001651 if tt.Size() == 4 {
1652 return s.uint64Tofloat32(n, x, ft, tt)
1653 }
1654 if tt.Size() == 8 {
1655 return s.uint64Tofloat64(n, x, ft, tt)
1656 }
David Chased052bbd2015-09-01 17:09:00 -04001657 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001658 }
David Chased052bbd2015-09-01 17:09:00 -04001659 // therefore ft is float32 or float64, and tt is unsigned integer
David Chase73151062015-08-26 14:25:40 -04001660 if ft.Size() == 4 {
David Chased052bbd2015-09-01 17:09:00 -04001661 return s.float32ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001662 }
David Chased052bbd2015-09-01 17:09:00 -04001663 if ft.Size() == 8 {
1664 return s.float64ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001665 }
David Chased052bbd2015-09-01 17:09:00 -04001666 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1667 return nil
David Chase42825882015-08-20 15:14:20 -04001668 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001669
1670 if ft.IsComplex() && tt.IsComplex() {
1671 var op ssa.Op
1672 if ft.Size() == tt.Size() {
1673 op = ssa.OpCopy
1674 } else if ft.Size() == 8 && tt.Size() == 16 {
1675 op = ssa.OpCvt32Fto64F
1676 } else if ft.Size() == 16 && tt.Size() == 8 {
1677 op = ssa.OpCvt64Fto32F
1678 } else {
1679 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1680 }
1681 ftp := floatForComplex(ft)
1682 ttp := floatForComplex(tt)
1683 return s.newValue2(ssa.OpComplexMake, tt,
1684 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1685 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1686 }
David Chase42825882015-08-20 15:14:20 -04001687
Keith Randall4304fbc2015-11-16 13:20:16 -08001688 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
Keith Randall2a5e6c42015-07-23 14:35:02 -07001689 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001690
Keith Randall269baa92015-09-17 10:31:16 -07001691 case ODOTTYPE:
1692 res, _ := s.dottype(n, false)
1693 return res
1694
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001695 // binary ops
1696 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001697 a := s.expr(n.Left)
1698 b := s.expr(n.Right)
Keith Randalldb380bf2015-09-10 11:05:42 -07001699 if n.Left.Type.IsComplex() {
Keith Randallc244ce02015-09-10 14:59:00 -07001700 pt := floatForComplex(n.Left.Type)
Keith Randalldb380bf2015-09-10 11:05:42 -07001701 op := s.ssaOp(OEQ, pt)
1702 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1703 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1704 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1705 switch n.Op {
1706 case OEQ:
1707 return c
1708 case ONE:
1709 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1710 default:
1711 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1712 }
Keith Randalldb380bf2015-09-10 11:05:42 -07001713 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001714 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
David Chase3a9d0ac2015-08-28 14:24:10 -04001715 case OMUL:
1716 a := s.expr(n.Left)
1717 b := s.expr(n.Right)
1718 if n.Type.IsComplex() {
1719 mulop := ssa.OpMul64F
1720 addop := ssa.OpAdd64F
1721 subop := ssa.OpSub64F
1722 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1723 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1724
1725 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1726 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1727 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1728 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1729
1730 if pt != wt { // Widen for calculation
1731 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1732 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1733 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1734 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1735 }
1736
1737 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1738 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1739
1740 if pt != wt { // Narrow to store back
1741 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1742 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1743 }
1744
1745 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1746 }
1747 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1748
1749 case ODIV:
1750 a := s.expr(n.Left)
1751 b := s.expr(n.Right)
1752 if n.Type.IsComplex() {
1753 // TODO this is not executed because the front-end substitutes a runtime call.
1754 // That probably ought to change; with modest optimization the widen/narrow
1755 // conversions could all be elided in larger expression trees.
1756 mulop := ssa.OpMul64F
1757 addop := ssa.OpAdd64F
1758 subop := ssa.OpSub64F
1759 divop := ssa.OpDiv64F
1760 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1761 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1762
1763 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1764 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1765 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1766 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1767
1768 if pt != wt { // Widen for calculation
1769 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1770 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1771 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1772 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1773 }
1774
1775 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1776 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1777 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1778
1779 // TODO not sure if this is best done in wide precision or narrow
1780 // Double-rounding might be an issue.
1781 // Note that the pre-SSA implementation does the entire calculation
1782 // in wide format, so wide is compatible.
1783 xreal = s.newValue2(divop, wt, xreal, denom)
1784 ximag = s.newValue2(divop, wt, ximag, denom)
1785
1786 if pt != wt { // Narrow to store back
1787 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1788 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1789 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001790 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1791 }
David Chase18559e22015-10-28 13:55:46 -04001792 if n.Type.IsFloat() {
1793 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1794 } else {
1795 // do a size-appropriate check for zero
1796 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1797 s.check(cmp, panicdivide)
1798 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1799 }
1800 case OMOD:
1801 a := s.expr(n.Left)
1802 b := s.expr(n.Right)
1803 // do a size-appropriate check for zero
1804 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1805 s.check(cmp, panicdivide)
David Chase3a9d0ac2015-08-28 14:24:10 -04001806 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1807 case OADD, OSUB:
1808 a := s.expr(n.Left)
1809 b := s.expr(n.Right)
1810 if n.Type.IsComplex() {
1811 pt := floatForComplex(n.Type)
1812 op := s.ssaOp(n.Op, pt)
1813 return s.newValue2(ssa.OpComplexMake, n.Type,
1814 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1815 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1816 }
1817 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
David Chase18559e22015-10-28 13:55:46 -04001818 case OAND, OOR, OHMUL, OXOR:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001819 a := s.expr(n.Left)
1820 b := s.expr(n.Right)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001821 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
Keith Randall4b803152015-07-29 17:07:09 -07001822 case OLSH, ORSH:
1823 a := s.expr(n.Left)
1824 b := s.expr(n.Right)
1825 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
David Chase40aba8c2015-08-05 22:11:14 -04001826 case OLROT:
1827 a := s.expr(n.Left)
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001828 i := n.Right.Int64()
David Chase40aba8c2015-08-05 22:11:14 -04001829 if i <= 0 || i >= n.Type.Size()*8 {
1830 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1831 }
1832 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001833 case OANDAND, OOROR:
1834 // To implement OANDAND (and OOROR), we introduce a
1835 // new temporary variable to hold the result. The
1836 // variable is associated with the OANDAND node in the
1837 // s.vars table (normally variables are only
1838 // associated with ONAME nodes). We convert
1839 // A && B
1840 // to
1841 // var = A
1842 // if var {
1843 // var = B
1844 // }
1845 // Using var in the subsequent block introduces the
1846 // necessary phi variable.
1847 el := s.expr(n.Left)
1848 s.vars[n] = el
1849
1850 b := s.endBlock()
1851 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07001852 b.SetControl(el)
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07001853 // In theory, we should set b.Likely here based on context.
1854 // However, gc only gives us likeliness hints
1855 // in a single place, for plain OIF statements,
1856 // and passing around context is finnicky, so don't bother for now.
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001857
1858 bRight := s.f.NewBlock(ssa.BlockPlain)
1859 bResult := s.f.NewBlock(ssa.BlockPlain)
1860 if n.Op == OANDAND {
Todd Neal47d67992015-08-28 21:36:29 -05001861 b.AddEdgeTo(bRight)
1862 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001863 } else if n.Op == OOROR {
Todd Neal47d67992015-08-28 21:36:29 -05001864 b.AddEdgeTo(bResult)
1865 b.AddEdgeTo(bRight)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001866 }
1867
1868 s.startBlock(bRight)
1869 er := s.expr(n.Right)
1870 s.vars[n] = er
1871
1872 b = s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05001873 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001874
1875 s.startBlock(bResult)
Josh Bleecher Snyder35ad1fc2015-08-27 10:11:08 -07001876 return s.variable(n, Types[TBOOL])
Keith Randall7e390722015-09-12 14:14:02 -07001877 case OCOMPLEX:
1878 r := s.expr(n.Left)
1879 i := s.expr(n.Right)
1880 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001881
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001882 // unary ops
David Chase3a9d0ac2015-08-28 14:24:10 -04001883 case OMINUS:
1884 a := s.expr(n.Left)
1885 if n.Type.IsComplex() {
1886 tp := floatForComplex(n.Type)
1887 negop := s.ssaOp(n.Op, tp)
1888 return s.newValue2(ssa.OpComplexMake, n.Type,
1889 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1890 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1891 }
1892 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randalla329e212015-09-12 13:26:57 -07001893 case ONOT, OCOM, OSQRT:
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001894 a := s.expr(n.Left)
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001895 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randall2f518072015-09-10 11:37:09 -07001896 case OIMAG, OREAL:
1897 a := s.expr(n.Left)
1898 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001899 case OPLUS:
1900 return s.expr(n.Left)
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001901
Keith Randallcfc2aa52015-05-18 16:44:20 -07001902 case OADDR:
David Chase57670ad2015-10-09 16:48:30 -04001903 return s.addr(n.Left, n.Bounded)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001904
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07001905 case OINDREG:
1906 if int(n.Reg) != Thearch.REGSP {
1907 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1908 return nil
1909 }
1910 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1911 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1912
Keith Randalld2fd43a2015-04-15 15:51:25 -07001913 case OIND:
1914 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001915 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -07001916 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001917
Keith Randallcd7e0592015-07-15 21:33:49 -07001918 case ODOT:
Keith Randalla734bbc2016-01-11 21:05:33 -08001919 t := n.Left.Type
1920 if canSSAType(t) {
1921 v := s.expr(n.Left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07001922 return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
Keith Randalla734bbc2016-01-11 21:05:33 -08001923 }
David Chase57670ad2015-10-09 16:48:30 -04001924 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001925 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcd7e0592015-07-15 21:33:49 -07001926
Keith Randalld2fd43a2015-04-15 15:51:25 -07001927 case ODOTPTR:
1928 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001929 s.nilCheck(p)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001930 p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
Keith Randall8f22b522015-06-11 21:29:25 -07001931 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001932
1933 case OINDEX:
Keith Randall97035642015-10-09 09:33:29 -07001934 switch {
1935 case n.Left.Type.IsString():
Keith Randallcfc2aa52015-05-18 16:44:20 -07001936 a := s.expr(n.Left)
1937 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001938 i = s.extendIndex(i)
Keith Randall97035642015-10-09 09:33:29 -07001939 if !n.Bounded {
1940 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1941 s.boundsCheck(i, len)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07001942 }
Keith Randall97035642015-10-09 09:33:29 -07001943 ptrtyp := Ptrto(Types[TUINT8])
1944 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001945 if Isconst(n.Right, CTINT) {
Josh Bleecher Snyder5cab0162016-04-01 14:51:02 -07001946 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int64(), ptr)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001947 } else {
1948 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1949 }
Keith Randall97035642015-10-09 09:33:29 -07001950 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1951 case n.Left.Type.IsSlice():
David Chase57670ad2015-10-09 16:48:30 -04001952 p := s.addr(n, false)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001953 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001954 case n.Left.Type.IsArray():
1955 // TODO: fix when we can SSA arrays of length 1.
David Chase57670ad2015-10-09 16:48:30 -04001956 p := s.addr(n, false)
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07001957 return s.newValue2(ssa.OpLoad, n.Left.Type.Elem(), p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001958 default:
1959 s.Fatalf("bad type for index %v", n.Left.Type)
1960 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001961 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07001962
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001963 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001964 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001965 case n.Left.Type.IsSlice():
1966 op := ssa.OpSliceLen
1967 if n.Op == OCAP {
1968 op = ssa.OpSliceCap
1969 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001970 return s.newValue1(op, Types[TINT], s.expr(n.Left))
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001971 case n.Left.Type.IsString(): // string; not reachable for OCAP
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001972 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
Todd Neal707af252015-08-28 15:56:43 -05001973 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1974 return s.referenceTypeBuiltin(n, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001975 default: // array
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07001976 return s.constInt(Types[TINT], n.Left.Type.NumElem())
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001977 }
1978
Josh Bleecher Snydera2d15802015-08-12 10:12:14 -07001979 case OSPTR:
1980 a := s.expr(n.Left)
1981 if n.Left.Type.IsSlice() {
1982 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1983 } else {
1984 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1985 }
1986
Keith Randalld1c15a02015-08-04 15:47:22 -07001987 case OITAB:
1988 a := s.expr(n.Left)
1989 return s.newValue1(ssa.OpITab, n.Type, a)
1990
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001991 case OEFACE:
1992 tab := s.expr(n.Left)
1993 data := s.expr(n.Right)
Keith Randall808d7c72015-10-07 14:35:25 -07001994 // The frontend allows putting things like struct{*byte} in
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001995 // the data portion of an eface. But we don't want struct{*byte}
Keith Randall808d7c72015-10-07 14:35:25 -07001996 // as a register type because (among other reasons) the liveness
1997 // analysis is confused by the "fat" variables that result from
1998 // such types being spilled.
1999 // So here we ensure that we are selecting the underlying pointer
2000 // when we build an eface.
Keith Randalla734bbc2016-01-11 21:05:33 -08002001 // TODO: get rid of this now that structs can be SSA'd?
Matthew Dempsky788f1122016-03-28 10:55:44 -07002002 for !data.Type.IsPtrShaped() {
Keith Randall808d7c72015-10-07 14:35:25 -07002003 switch {
2004 case data.Type.IsArray():
Matthew Dempsky0b281872016-03-10 14:35:39 -08002005 data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
Keith Randall808d7c72015-10-07 14:35:25 -07002006 case data.Type.IsStruct():
2007 for i := data.Type.NumFields() - 1; i >= 0; i-- {
2008 f := data.Type.FieldType(i)
2009 if f.Size() == 0 {
2010 // eface type could also be struct{p *byte; q [0]int}
2011 continue
2012 }
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002013 data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
Keith Randall808d7c72015-10-07 14:35:25 -07002014 break
2015 }
2016 default:
2017 s.Fatalf("type being put into an eface isn't a pointer")
2018 }
2019 }
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07002020 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
2021
Keith Randall5505e8c2015-09-12 23:27:26 -07002022 case OSLICE, OSLICEARR:
2023 v := s.expr(n.Left)
2024 var i, j *ssa.Value
2025 if n.Right.Left != nil {
2026 i = s.extendIndex(s.expr(n.Right.Left))
2027 }
2028 if n.Right.Right != nil {
2029 j = s.extendIndex(s.expr(n.Right.Right))
2030 }
2031 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
2032 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07002033 case OSLICESTR:
Keith Randall5505e8c2015-09-12 23:27:26 -07002034 v := s.expr(n.Left)
2035 var i, j *ssa.Value
2036 if n.Right.Left != nil {
2037 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07002038 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002039 if n.Right.Right != nil {
2040 j = s.extendIndex(s.expr(n.Right.Right))
Keith Randall3526cf52015-08-24 23:52:03 -07002041 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002042 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
2043 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
2044 case OSLICE3, OSLICE3ARR:
2045 v := s.expr(n.Left)
2046 var i *ssa.Value
2047 if n.Right.Left != nil {
2048 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07002049 }
Keith Randall5505e8c2015-09-12 23:27:26 -07002050 j := s.extendIndex(s.expr(n.Right.Right.Left))
2051 k := s.extendIndex(s.expr(n.Right.Right.Right))
2052 p, l, c := s.slice(n.Left.Type, v, i, j, k)
2053 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07002054
David Chase8eec2bb2016-03-11 00:10:52 -05002055 case OCALLFUNC:
2056 if isIntrinsicCall1(n) {
2057 return s.intrinsicCall1(n)
2058 }
2059 fallthrough
2060
2061 case OCALLINTER, OCALLMETH:
Keith Randall5ba31942016-01-25 17:06:54 -08002062 a := s.call(n, callNormal)
2063 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002064
2065 case OGETG:
Keith Randalld694f832015-10-19 18:54:40 -07002066 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002067
Keith Randall9d22c102015-09-11 11:02:57 -07002068 case OAPPEND:
2069 // append(s, e1, e2, e3). Compile like:
2070 // ptr,len,cap := s
2071 // newlen := len + 3
2072 // if newlen > s.cap {
2073 // ptr,_,cap = growslice(s, newlen)
2074 // }
2075 // *(ptr+len) = e1
2076 // *(ptr+len+1) = e2
2077 // *(ptr+len+2) = e3
2078 // makeslice(ptr,newlen,cap)
2079
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002080 et := n.Type.Elem()
Keith Randall9d22c102015-09-11 11:02:57 -07002081 pt := Ptrto(et)
2082
2083 // Evaluate slice
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002084 slice := s.expr(n.List.First())
Keith Randall9d22c102015-09-11 11:02:57 -07002085
Keith Randall9d22c102015-09-11 11:02:57 -07002086 // Allocate new blocks
2087 grow := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002088 assign := s.f.NewBlock(ssa.BlockPlain)
2089
2090 // Decide if we need to grow
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002091 nargs := int64(n.List.Len() - 1)
Keith Randall9d22c102015-09-11 11:02:57 -07002092 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2093 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2094 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2095 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2096 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
Keith Randallb32217a2015-09-17 16:45:10 -07002097 s.vars[&ptrVar] = p
2098 s.vars[&capVar] = c
Keith Randall9d22c102015-09-11 11:02:57 -07002099 b := s.endBlock()
2100 b.Kind = ssa.BlockIf
2101 b.Likely = ssa.BranchUnlikely
Keith Randall56e0ecc2016-03-15 20:45:50 -07002102 b.SetControl(cmp)
Keith Randall9d22c102015-09-11 11:02:57 -07002103 b.AddEdgeTo(grow)
2104 b.AddEdgeTo(assign)
2105
2106 // Call growslice
2107 s.startBlock(grow)
2108 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
2109
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002110 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
Keith Randall9d22c102015-09-11 11:02:57 -07002111
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002112 s.vars[&ptrVar] = r[0]
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002113 // Note: we don't need to read r[1], the result's length. It will be nl.
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002114 // (or maybe we should, we just have to spill/restore nl otherwise?)
2115 s.vars[&capVar] = r[2]
Keith Randall9d22c102015-09-11 11:02:57 -07002116 b = s.endBlock()
2117 b.AddEdgeTo(assign)
2118
2119 // assign new elements to slots
2120 s.startBlock(assign)
Keith Randall9aba7e72015-10-05 13:48:40 -07002121
2122 // Evaluate args
2123 args := make([]*ssa.Value, 0, nargs)
Keith Randall808d7c72015-10-07 14:35:25 -07002124 store := make([]bool, 0, nargs)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002125 for _, n := range n.List.Slice()[1:] {
2126 if canSSAType(n.Type) {
2127 args = append(args, s.expr(n))
Keith Randall808d7c72015-10-07 14:35:25 -07002128 store = append(store, true)
2129 } else {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002130 args = append(args, s.addr(n, false))
Keith Randall808d7c72015-10-07 14:35:25 -07002131 store = append(store, false)
2132 }
Keith Randall9aba7e72015-10-05 13:48:40 -07002133 }
2134
Keith Randallb32217a2015-09-17 16:45:10 -07002135 p = s.variable(&ptrVar, pt) // generates phi for ptr
2136 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
Keith Randall9d22c102015-09-11 11:02:57 -07002137 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
Keith Randall5ba31942016-01-25 17:06:54 -08002138 // TODO: just one write barrier call for all of these writes?
2139 // TODO: maybe just one writeBarrier.enabled check?
Keith Randall9d22c102015-09-11 11:02:57 -07002140 for i, arg := range args {
Keith Randall582baae2015-11-02 21:28:13 -08002141 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
Keith Randall808d7c72015-10-07 14:35:25 -07002142 if store[i] {
Keith Randall5ba31942016-01-25 17:06:54 -08002143 if haspointers(et) {
Keith Randalld4663e12016-03-21 10:22:03 -07002144 s.insertWBstore(et, addr, arg, n.Lineno, 0)
Keith Randall5ba31942016-01-25 17:06:54 -08002145 } else {
2146 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2147 }
Keith Randall808d7c72015-10-07 14:35:25 -07002148 } else {
Keith Randall5ba31942016-01-25 17:06:54 -08002149 if haspointers(et) {
2150 s.insertWBmove(et, addr, arg, n.Lineno)
2151 } else {
2152 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2153 }
Keith Randall9d22c102015-09-11 11:02:57 -07002154 }
2155 }
2156
2157 // make result
Keith Randallb32217a2015-09-17 16:45:10 -07002158 delete(s.vars, &ptrVar)
2159 delete(s.vars, &capVar)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002160 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
Keith Randall9d22c102015-09-11 11:02:57 -07002161
Keith Randalld2fd43a2015-04-15 15:51:25 -07002162 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07002163 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -07002164 return nil
2165 }
2166}
2167
Keith Randall99187312015-11-02 16:56:53 -08002168// condBranch evaluates the boolean expression cond and branches to yes
2169// if cond is true and no if cond is false.
2170// This function is intended to handle && and || better than just calling
2171// s.expr(cond) and branching on the result.
2172func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2173 if cond.Op == OANDAND {
2174 mid := s.f.NewBlock(ssa.BlockPlain)
2175 s.stmtList(cond.Ninit)
2176 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2177 s.startBlock(mid)
2178 s.condBranch(cond.Right, yes, no, likely)
2179 return
2180 // Note: if likely==1, then both recursive calls pass 1.
2181 // If likely==-1, then we don't have enough information to decide
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002182 // whether the first branch is likely or not. So we pass 0 for
Keith Randall99187312015-11-02 16:56:53 -08002183 // the likeliness of the first branch.
2184 // TODO: have the frontend give us branch prediction hints for
2185 // OANDAND and OOROR nodes (if it ever has such info).
2186 }
2187 if cond.Op == OOROR {
2188 mid := s.f.NewBlock(ssa.BlockPlain)
2189 s.stmtList(cond.Ninit)
2190 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2191 s.startBlock(mid)
2192 s.condBranch(cond.Right, yes, no, likely)
2193 return
2194 // Note: if likely==-1, then both recursive calls pass -1.
2195 // If likely==1, then we don't have enough info to decide
2196 // the likelihood of the first branch.
2197 }
Keith Randalld19bfc32015-11-03 09:30:17 -08002198 if cond.Op == ONOT {
2199 s.stmtList(cond.Ninit)
2200 s.condBranch(cond.Left, no, yes, -likely)
2201 return
2202 }
Keith Randall99187312015-11-02 16:56:53 -08002203 c := s.expr(cond)
2204 b := s.endBlock()
2205 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07002206 b.SetControl(c)
Keith Randall99187312015-11-02 16:56:53 -08002207 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2208 b.AddEdgeTo(yes)
2209 b.AddEdgeTo(no)
2210}
2211
Keith Randalld4663e12016-03-21 10:22:03 -07002212type skipMask uint8
2213
2214const (
2215 skipPtr skipMask = 1 << iota
2216 skipLen
2217 skipCap
2218)
2219
Keith Randall5ba31942016-01-25 17:06:54 -08002220// assign does left = right.
2221// Right has already been evaluated to ssa, left has not.
2222// If deref is true, then we do left = *right instead (and right has already been nil-checked).
2223// If deref is true and right == nil, just do left = 0.
2224// Include a write barrier if wb is true.
Keith Randalld4663e12016-03-21 10:22:03 -07002225// skip indicates assignments (at the top level) that can be avoided.
2226func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32, skip skipMask) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002227 if left.Op == ONAME && isblank(left) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002228 return
2229 }
Keith Randalld4cc51d2015-08-14 21:47:20 -07002230 t := left.Type
2231 dowidth(t)
Keith Randall6a8a9da2016-02-27 17:49:31 -08002232 if s.canSSA(left) {
Keith Randall5ba31942016-01-25 17:06:54 -08002233 if deref {
2234 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2235 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002236 if left.Op == ODOT {
2237 // We're assigning to a field of an ssa-able value.
2238 // We need to build a new structure with the new value for the
2239 // field we're assigning and the old values for the other fields.
2240 // For instance:
2241 // type T struct {a, b, c int}
2242 // var T x
2243 // x.b = 5
2244 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2245
2246 // Grab information about the structure type.
2247 t := left.Left.Type
2248 nf := t.NumFields()
2249 idx := fieldIdx(left)
2250
2251 // Grab old value of structure.
2252 old := s.expr(left.Left)
2253
2254 // Make new structure.
2255 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2256
2257 // Add fields as args.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002258 for i := 0; i < nf; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002259 if i == idx {
2260 new.AddArg(right)
2261 } else {
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002262 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
Keith Randalla734bbc2016-01-11 21:05:33 -08002263 }
2264 }
2265
2266 // Recursively assign the new value we've made to the base of the dot op.
Keith Randalld4663e12016-03-21 10:22:03 -07002267 s.assign(left.Left, new, false, false, line, 0)
Keith Randalla734bbc2016-01-11 21:05:33 -08002268 // TODO: do we need to update named values here?
2269 return
2270 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002271 // Update variable assignment.
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002272 s.vars[left] = right
Keith Randallc24681a2015-10-22 14:22:38 -07002273 s.addNamedValue(left, right)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002274 return
2275 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002276 // Left is not ssa-able. Compute its address.
David Chase57670ad2015-10-09 16:48:30 -04002277 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002278 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002279 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002280 }
Keith Randall5ba31942016-01-25 17:06:54 -08002281 if deref {
2282 // Treat as a mem->mem move.
2283 if right == nil {
2284 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2285 return
2286 }
2287 if wb {
2288 s.insertWBmove(t, addr, right, line)
2289 return
2290 }
2291 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2292 return
Keith Randalle3869a62015-09-07 23:18:02 -07002293 }
Keith Randall5ba31942016-01-25 17:06:54 -08002294 // Treat as a store.
2295 if wb {
Keith Randalld4663e12016-03-21 10:22:03 -07002296 if skip&skipPtr != 0 {
2297 // Special case: if we don't write back the pointers, don't bother
2298 // doing the write barrier check.
2299 s.storeTypeScalars(t, addr, right, skip)
2300 return
2301 }
2302 s.insertWBstore(t, addr, right, line, skip)
2303 return
2304 }
2305 if skip != 0 {
2306 if skip&skipPtr == 0 {
2307 s.storeTypePtrs(t, addr, right)
2308 }
2309 s.storeTypeScalars(t, addr, right, skip)
Keith Randall5ba31942016-01-25 17:06:54 -08002310 return
2311 }
2312 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002313}
2314
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002315// zeroVal returns the zero value for type t.
2316func (s *state) zeroVal(t *Type) *ssa.Value {
2317 switch {
Keith Randall9cb332e2015-07-28 14:19:20 -07002318 case t.IsInteger():
2319 switch t.Size() {
2320 case 1:
2321 return s.constInt8(t, 0)
2322 case 2:
2323 return s.constInt16(t, 0)
2324 case 4:
2325 return s.constInt32(t, 0)
2326 case 8:
2327 return s.constInt64(t, 0)
2328 default:
2329 s.Fatalf("bad sized integer type %s", t)
2330 }
Todd Neal752fe4d2015-08-25 19:21:45 -05002331 case t.IsFloat():
2332 switch t.Size() {
2333 case 4:
2334 return s.constFloat32(t, 0)
2335 case 8:
2336 return s.constFloat64(t, 0)
2337 default:
2338 s.Fatalf("bad sized float type %s", t)
2339 }
David Chase52578582015-08-28 14:24:10 -04002340 case t.IsComplex():
2341 switch t.Size() {
2342 case 8:
2343 z := s.constFloat32(Types[TFLOAT32], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002344 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002345 case 16:
2346 z := s.constFloat64(Types[TFLOAT64], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002347 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002348 default:
2349 s.Fatalf("bad sized complex type %s", t)
2350 }
2351
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002352 case t.IsString():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002353 return s.constEmptyString(t)
Matthew Dempsky788f1122016-03-28 10:55:44 -07002354 case t.IsPtrShaped():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002355 return s.constNil(t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002356 case t.IsBoolean():
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07002357 return s.constBool(false)
Keith Randall9f954db2015-08-18 10:26:28 -07002358 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002359 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07002360 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002361 return s.constSlice(t)
Keith Randalla734bbc2016-01-11 21:05:33 -08002362 case t.IsStruct():
2363 n := t.NumFields()
2364 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002365 for i := 0; i < n; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002366 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2367 }
2368 return v
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002369 }
2370 s.Unimplementedf("zero for type %v not implemented", t)
2371 return nil
2372}
2373
Keith Randalld24768e2015-09-09 23:56:59 -07002374type callKind int8
2375
2376const (
2377 callNormal callKind = iota
2378 callDefer
2379 callGo
2380)
2381
David Chase8eec2bb2016-03-11 00:10:52 -05002382// isSSAIntrinsic1 returns true if n is a call to a recognized 1-arg intrinsic
2383// that can be handled by the SSA backend.
2384// SSA uses this, but so does the front end to see if should not
2385// inline a function because it is a candidate for intrinsic
2386// substitution.
2387func isSSAIntrinsic1(s *Sym) bool {
2388 // The test below is not quite accurate -- in the event that
2389 // a function is disabled on a per-function basis, for example
2390 // because of hash-keyed binary failure search, SSA might be
2391 // disabled for that function but it would not be noted here,
2392 // and thus an inlining would not occur (in practice, inlining
2393 // so far has only been noticed for Bswap32 and the 16-bit count
2394 // leading/trailing instructions, but heuristics might change
2395 // in the future or on different architectures).
2396 if !ssaEnabled || ssa.IntrinsicsDisable || Thearch.Thechar != '6' {
2397 return false
2398 }
2399 if s != nil && s.Pkg != nil && s.Pkg.Path == "runtime/internal/sys" {
2400 switch s.Name {
2401 case
2402 "Ctz64", "Ctz32", "Ctz16",
2403 "Bswap64", "Bswap32":
2404 return true
2405 }
2406 }
2407 return false
2408}
2409
2410func isIntrinsicCall1(n *Node) bool {
2411 if n == nil || n.Left == nil {
2412 return false
2413 }
2414 return isSSAIntrinsic1(n.Left.Sym)
2415}
2416
2417// intrinsicFirstArg extracts arg from n.List and eval
2418func (s *state) intrinsicFirstArg(n *Node) *ssa.Value {
2419 x := n.List.First()
2420 if x.Op == OAS {
2421 x = x.Right
2422 }
2423 return s.expr(x)
2424}
2425
2426// intrinsicCall1 converts a call to a recognized 1-arg intrinsic
2427// into the intrinsic
2428func (s *state) intrinsicCall1(n *Node) *ssa.Value {
2429 var result *ssa.Value
2430 switch n.Left.Sym.Name {
2431 case "Ctz64":
2432 result = s.newValue1(ssa.OpCtz64, Types[TUINT64], s.intrinsicFirstArg(n))
2433 case "Ctz32":
2434 result = s.newValue1(ssa.OpCtz32, Types[TUINT32], s.intrinsicFirstArg(n))
2435 case "Ctz16":
2436 result = s.newValue1(ssa.OpCtz16, Types[TUINT16], s.intrinsicFirstArg(n))
2437 case "Bswap64":
2438 result = s.newValue1(ssa.OpBswap64, Types[TUINT64], s.intrinsicFirstArg(n))
2439 case "Bswap32":
2440 result = s.newValue1(ssa.OpBswap32, Types[TUINT32], s.intrinsicFirstArg(n))
2441 }
2442 if result == nil {
2443 Fatalf("Unknown special call: %v", n.Left.Sym)
2444 }
2445 if ssa.IntrinsicsDebug > 0 {
2446 Warnl(n.Lineno, "intrinsic substitution for %v with %s", n.Left.Sym.Name, result.LongString())
2447 }
2448 return result
2449}
2450
Keith Randall5ba31942016-01-25 17:06:54 -08002451// Calls the function n using the specified call type.
2452// Returns the address of the return value (or nil if none).
Keith Randalld24768e2015-09-09 23:56:59 -07002453func (s *state) call(n *Node, k callKind) *ssa.Value {
2454 var sym *Sym // target symbol (if static)
2455 var closure *ssa.Value // ptr to closure to run (if dynamic)
2456 var codeptr *ssa.Value // ptr to target code (if dynamic)
2457 var rcvr *ssa.Value // receiver to set
2458 fn := n.Left
2459 switch n.Op {
2460 case OCALLFUNC:
2461 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2462 sym = fn.Sym
2463 break
2464 }
2465 closure = s.expr(fn)
Keith Randalld24768e2015-09-09 23:56:59 -07002466 case OCALLMETH:
2467 if fn.Op != ODOTMETH {
2468 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2469 }
Keith Randalld24768e2015-09-09 23:56:59 -07002470 if k == callNormal {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002471 sym = fn.Sym
Keith Randalld24768e2015-09-09 23:56:59 -07002472 break
2473 }
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002474 n2 := newname(fn.Sym)
Keith Randalld24768e2015-09-09 23:56:59 -07002475 n2.Class = PFUNC
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07002476 n2.Lineno = fn.Lineno
2477 closure = s.expr(n2)
Keith Randalld24768e2015-09-09 23:56:59 -07002478 // Note: receiver is already assigned in n.List, so we don't
2479 // want to set it here.
2480 case OCALLINTER:
2481 if fn.Op != ODOTINTER {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002482 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(fn.Op, 0))
Keith Randalld24768e2015-09-09 23:56:59 -07002483 }
2484 i := s.expr(fn.Left)
2485 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2486 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2487 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2488 if k == callNormal {
2489 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2490 } else {
2491 closure = itab
2492 }
2493 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2494 }
2495 dowidth(fn.Type)
Josh Bleecher Snyder361b3342016-03-28 14:31:57 -07002496 stksize := fn.Type.ArgWidth() // includes receiver
Keith Randalld24768e2015-09-09 23:56:59 -07002497
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002498 // Run all argument assignments. The arg slots have already
Keith Randalld24768e2015-09-09 23:56:59 -07002499 // been offset by the appropriate amount (+2*widthptr for go/defer,
2500 // +widthptr for interface calls).
2501 // For OCALLMETH, the receiver is set in these statements.
2502 s.stmtList(n.List)
2503
2504 // Set receiver (for interface calls)
2505 if rcvr != nil {
Keith Randall7c4fbb62015-10-19 13:56:55 -07002506 argStart := Ctxt.FixedFrameSize()
Keith Randalld24768e2015-09-09 23:56:59 -07002507 if k != callNormal {
2508 argStart += int64(2 * Widthptr)
2509 }
2510 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002511 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002512 }
2513
2514 // Defer/go args
2515 if k != callNormal {
2516 // Write argsize and closure (args to Newproc/Deferproc).
2517 argsize := s.constInt32(Types[TUINT32], int32(stksize))
Keith Randallb32217a2015-09-17 16:45:10 -07002518 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002519 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002520 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002521 stksize += 2 * int64(Widthptr)
2522 }
2523
2524 // call target
2525 bNext := s.f.NewBlock(ssa.BlockPlain)
2526 var call *ssa.Value
2527 switch {
2528 case k == callDefer:
2529 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2530 case k == callGo:
2531 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2532 case closure != nil:
2533 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2534 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2535 case codeptr != nil:
2536 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2537 case sym != nil:
2538 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2539 default:
2540 Fatalf("bad call type %s %v", opnames[n.Op], n)
2541 }
2542 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2543
2544 // Finish call block
Keith Randallb32217a2015-09-17 16:45:10 -07002545 s.vars[&memVar] = call
Keith Randalld24768e2015-09-09 23:56:59 -07002546 b := s.endBlock()
2547 b.Kind = ssa.BlockCall
Keith Randall56e0ecc2016-03-15 20:45:50 -07002548 b.SetControl(call)
Keith Randalld24768e2015-09-09 23:56:59 -07002549 b.AddEdgeTo(bNext)
Keith Randallddc6b642016-03-09 19:27:57 -08002550 if k == callDefer {
2551 // Add recover edge to exit code.
2552 b.Kind = ssa.BlockDefer
2553 r := s.f.NewBlock(ssa.BlockPlain)
2554 s.startBlock(r)
2555 s.exit()
2556 b.AddEdgeTo(r)
2557 b.Likely = ssa.BranchLikely
2558 }
Keith Randalld24768e2015-09-09 23:56:59 -07002559
Keith Randall5ba31942016-01-25 17:06:54 -08002560 // Start exit block, find address of result.
Keith Randalld24768e2015-09-09 23:56:59 -07002561 s.startBlock(bNext)
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002562 res := n.Left.Type.Results()
2563 if res.NumFields() == 0 || k != callNormal {
Keith Randalld24768e2015-09-09 23:56:59 -07002564 // call has no return value. Continue with the next statement.
2565 return nil
2566 }
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002567 fp := res.Field(0)
Matthew Dempsky62dddd42016-03-28 09:40:53 -07002568 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Offset, s.sp)
Keith Randalld24768e2015-09-09 23:56:59 -07002569}
2570
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002571// etypesign returns the signed-ness of e, for integer/pointer etypes.
2572// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
Keith Randall4304fbc2015-11-16 13:20:16 -08002573func etypesign(e EType) int8 {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002574 switch e {
2575 case TINT8, TINT16, TINT32, TINT64, TINT:
2576 return -1
2577 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2578 return +1
2579 }
2580 return 0
2581}
2582
Todd Neald076ef72015-10-15 20:25:32 -05002583// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2584// This improves the effectiveness of cse by using the same Aux values for the
2585// same symbols.
2586func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2587 switch sym.(type) {
2588 default:
2589 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2590 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2591 // these are the only valid types
2592 }
2593
2594 if lsym, ok := s.varsyms[n]; ok {
2595 return lsym
2596 } else {
2597 s.varsyms[n] = sym
2598 return sym
2599 }
2600}
2601
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07002602// 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 -07002603// The value that the returned Value represents is guaranteed to be non-nil.
David Chase57670ad2015-10-09 16:48:30 -04002604// If bounded is true then this address does not require a nil check for its operand
2605// even if that would otherwise be implied.
2606func (s *state) addr(n *Node, bounded bool) *ssa.Value {
Keith Randallc24681a2015-10-22 14:22:38 -07002607 t := Ptrto(n.Type)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002608 switch n.Op {
2609 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07002610 switch n.Class {
2611 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -07002612 // global variable
Todd Neal74180dd2015-10-27 21:35:48 -05002613 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
Keith Randallc24681a2015-10-22 14:22:38 -07002614 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
Josh Bleecher Snyder67df7932015-07-28 11:08:44 -07002615 // TODO: Make OpAddr use AuxInt as well as Aux.
2616 if n.Xoffset != 0 {
2617 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2618 }
2619 return v
David Chase956f3192015-09-11 16:40:05 -04002620 case PPARAM:
2621 // parameter slot
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002622 v := s.decladdrs[n]
Keith Randall4304fbc2015-11-16 13:20:16 -08002623 if v != nil {
2624 return v
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002625 }
Keith Randall4304fbc2015-11-16 13:20:16 -08002626 if n.String() == ".fp" {
2627 // Special arg that points to the frame pointer.
2628 // (Used by the race detector, others?)
2629 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2630 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2631 }
2632 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2633 return nil
Keith Randalld2107fc2015-08-24 02:16:19 -07002634 case PAUTO:
Todd Neal40bfec02016-03-11 20:03:17 -06002635 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002636 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002637 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
Todd Neald076ef72015-10-15 20:25:32 -05002638 // ensure that we reuse symbols for out parameters so
2639 // that cse works on their addresses
2640 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002641 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002642 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002643 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -07002644 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002645 s.Unimplementedf("variable address class %v not implemented", n.Class)
Keith Randall290d8fc2015-06-10 15:03:06 -07002646 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07002647 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002648 case OINDREG:
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002649 // indirect off a register
Keith Randallcfc2aa52015-05-18 16:44:20 -07002650 // used for storing/loading arguments/returns to/from callees
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002651 if int(n.Reg) != Thearch.REGSP {
2652 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2653 return nil
2654 }
Keith Randallc24681a2015-10-22 14:22:38 -07002655 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002656 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002657 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002658 a := s.expr(n.Left)
2659 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002660 i = s.extendIndex(i)
Keith Randallc24681a2015-10-22 14:22:38 -07002661 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
Keith Randall46e62f82015-08-18 14:17:30 -07002662 if !n.Bounded {
2663 s.boundsCheck(i, len)
2664 }
Keith Randallc24681a2015-10-22 14:22:38 -07002665 p := s.newValue1(ssa.OpSlicePtr, t, a)
2666 return s.newValue2(ssa.OpPtrIndex, t, p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002667 } else { // array
David Chase57670ad2015-10-09 16:48:30 -04002668 a := s.addr(n.Left, bounded)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002669 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002670 i = s.extendIndex(i)
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07002671 len := s.constInt(Types[TINT], n.Left.Type.NumElem())
Keith Randall46e62f82015-08-18 14:17:30 -07002672 if !n.Bounded {
2673 s.boundsCheck(i, len)
2674 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07002675 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Elem()), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002676 }
Todd Nealb383de22015-07-13 21:22:16 -05002677 case OIND:
2678 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002679 if !bounded {
2680 s.nilCheck(p)
2681 }
Todd Nealb383de22015-07-13 21:22:16 -05002682 return p
Keith Randallc3c84a22015-07-13 15:55:37 -07002683 case ODOT:
David Chase57670ad2015-10-09 16:48:30 -04002684 p := s.addr(n.Left, bounded)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002685 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
Keith Randallc3c84a22015-07-13 15:55:37 -07002686 case ODOTPTR:
2687 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002688 if !bounded {
2689 s.nilCheck(p)
2690 }
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002691 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
David Chase956f3192015-09-11 16:40:05 -04002692 case OCLOSUREVAR:
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002693 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
2694 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
David Chase32ffbf72015-10-08 17:14:12 -04002695 case OPARAM:
2696 p := n.Left
2697 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2698 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2699 }
2700
2701 // Recover original offset to address passed-in param value.
2702 original_p := *p
2703 original_p.Xoffset = n.Xoffset
2704 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
Keith Randallc24681a2015-10-22 14:22:38 -07002705 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase57670ad2015-10-09 16:48:30 -04002706 case OCONVNOP:
2707 addr := s.addr(n.Left, bounded)
Keith Randallc24681a2015-10-22 14:22:38 -07002708 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
Keith Randall5ba31942016-01-25 17:06:54 -08002709 case OCALLFUNC, OCALLINTER, OCALLMETH:
2710 return s.call(n, callNormal)
David Chase57670ad2015-10-09 16:48:30 -04002711
Keith Randallcfc2aa52015-05-18 16:44:20 -07002712 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002713 s.Unimplementedf("unhandled addr %v", Oconv(n.Op, 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -07002714 return nil
2715 }
2716}
2717
Keith Randall290d8fc2015-06-10 15:03:06 -07002718// canSSA reports whether n is SSA-able.
Keith Randalla734bbc2016-01-11 21:05:33 -08002719// n must be an ONAME (or an ODOT sequence with an ONAME base).
Keith Randall6a8a9da2016-02-27 17:49:31 -08002720func (s *state) canSSA(n *Node) bool {
Keith Randalla734bbc2016-01-11 21:05:33 -08002721 for n.Op == ODOT {
2722 n = n.Left
2723 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002724 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +01002725 return false
Keith Randall290d8fc2015-06-10 15:03:06 -07002726 }
2727 if n.Addrtaken {
2728 return false
2729 }
2730 if n.Class&PHEAP != 0 {
2731 return false
2732 }
Josh Bleecher Snyder96548732015-08-28 13:35:32 -07002733 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -08002734 case PEXTERN, PPARAMREF:
2735 // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
Keith Randall290d8fc2015-06-10 15:03:06 -07002736 return false
Keith Randall6a8a9da2016-02-27 17:49:31 -08002737 case PPARAMOUT:
2738 if hasdefer {
2739 // TODO: handle this case? Named return values must be
2740 // in memory so that the deferred function can see them.
2741 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
2742 return false
2743 }
2744 if s.cgoUnsafeArgs {
2745 // Cgo effectively takes the address of all result args,
2746 // but the compiler can't see that.
2747 return false
2748 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002749 }
Keith Randall8a1f6212015-09-08 21:28:44 -07002750 if n.Class == PPARAM && n.String() == ".this" {
2751 // wrappers generated by genwrapper need to update
2752 // the .this pointer in place.
Keith Randall6a8a9da2016-02-27 17:49:31 -08002753 // TODO: treat as a PPARMOUT?
Keith Randall8a1f6212015-09-08 21:28:44 -07002754 return false
2755 }
Keith Randall9f954db2015-08-18 10:26:28 -07002756 return canSSAType(n.Type)
2757 // TODO: try to make more variables SSAable?
2758}
2759
2760// canSSA reports whether variables of type t are SSA-able.
2761func canSSAType(t *Type) bool {
2762 dowidth(t)
2763 if t.Width > int64(4*Widthptr) {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002764 // 4*Widthptr is an arbitrary constant. We want it
Keith Randall9f954db2015-08-18 10:26:28 -07002765 // to be at least 3*Widthptr so slices can be registerized.
2766 // Too big and we'll introduce too much register pressure.
Daniel Morsing66b47812015-06-27 15:45:20 +01002767 return false
2768 }
Keith Randall9f954db2015-08-18 10:26:28 -07002769 switch t.Etype {
2770 case TARRAY:
Matthew Dempsky1624a9c2016-03-30 14:45:47 -07002771 if t.IsSlice() {
Keith Randall9f954db2015-08-18 10:26:28 -07002772 return true
2773 }
2774 // We can't do arrays because dynamic indexing is
2775 // not supported on SSA variables.
2776 // TODO: maybe allow if length is <=1? All indexes
2777 // are constant? Might be good for the arrays
2778 // introduced by the compiler for variadic functions.
2779 return false
2780 case TSTRUCT:
Matthew Dempskydbed1c62016-03-17 13:26:08 -07002781 if t.NumFields() > ssa.MaxStruct {
Keith Randall9f954db2015-08-18 10:26:28 -07002782 return false
2783 }
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07002784 for _, t1 := range t.Fields().Slice() {
Keith Randall9f954db2015-08-18 10:26:28 -07002785 if !canSSAType(t1.Type) {
2786 return false
2787 }
2788 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002789 return true
Keith Randall9f954db2015-08-18 10:26:28 -07002790 default:
2791 return true
2792 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002793}
2794
Keith Randallcfc2aa52015-05-18 16:44:20 -07002795// nilCheck generates nil pointer checking code.
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002796// Starts a new block on return, unless nil checks are disabled.
Josh Bleecher Snyder7e74e432015-07-24 11:55:52 -07002797// Used only for automatically inserted nil checks,
2798// not for user code like 'x != nil'.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002799func (s *state) nilCheck(ptr *ssa.Value) {
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002800 if Disable_checknil != 0 {
2801 return
2802 }
Keith Randall31115a52015-10-23 19:12:49 -07002803 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07002804 b := s.endBlock()
Keith Randall31115a52015-10-23 19:12:49 -07002805 b.Kind = ssa.BlockCheck
Keith Randall56e0ecc2016-03-15 20:45:50 -07002806 b.SetControl(chk)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002807 bNext := s.f.NewBlock(ssa.BlockPlain)
Todd Neal47d67992015-08-28 21:36:29 -05002808 b.AddEdgeTo(bNext)
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002809 s.startBlock(bNext)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002810}
2811
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002812// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002813// Starts a new block on return.
2814func (s *state) boundsCheck(idx, len *ssa.Value) {
Keith Randall8d236812015-08-18 15:25:40 -07002815 if Debug['B'] != 0 {
2816 return
2817 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002818 // TODO: convert index to full width?
2819 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2820
2821 // bounds check
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002822 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002823 s.check(cmp, Panicindex)
Keith Randall3526cf52015-08-24 23:52:03 -07002824}
2825
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002826// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
Keith Randall3526cf52015-08-24 23:52:03 -07002827// Starts a new block on return.
2828func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2829 if Debug['B'] != 0 {
2830 return
2831 }
2832 // TODO: convert index to full width?
2833 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2834
2835 // bounds check
2836 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002837 s.check(cmp, panicslice)
Keith Randall3526cf52015-08-24 23:52:03 -07002838}
2839
Keith Randall3a70bf92015-09-17 16:54:15 -07002840// If cmp (a bool) is true, panic using the given function.
2841func (s *state) check(cmp *ssa.Value, fn *Node) {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002842 b := s.endBlock()
2843 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07002844 b.SetControl(cmp)
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07002845 b.Likely = ssa.BranchLikely
Keith Randallcfc2aa52015-05-18 16:44:20 -07002846 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall74e568f2015-11-09 21:35:40 -08002847 line := s.peekLine()
2848 bPanic := s.panics[funcLine{fn, line}]
2849 if bPanic == nil {
2850 bPanic = s.f.NewBlock(ssa.BlockPlain)
2851 s.panics[funcLine{fn, line}] = bPanic
2852 s.startBlock(bPanic)
2853 // The panic call takes/returns memory to ensure that the right
2854 // memory state is observed if the panic happens.
2855 s.rtcall(fn, false, nil)
2856 }
Todd Neal47d67992015-08-28 21:36:29 -05002857 b.AddEdgeTo(bNext)
2858 b.AddEdgeTo(bPanic)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002859 s.startBlock(bNext)
2860}
2861
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002862// rtcall issues a call to the given runtime function fn with the listed args.
2863// Returns a slice of results of the given result types.
2864// The call is added to the end of the current block.
2865// If returns is false, the block is marked as an exit block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002866// If returns is true, the block is marked as a call block. A new block
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002867// is started to load the return values.
2868func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2869 // Write args to the stack
2870 var off int64 // TODO: arch-dependent starting offset?
2871 for _, arg := range args {
2872 t := arg.Type
2873 off = Rnd(off, t.Alignment())
2874 ptr := s.sp
2875 if off != 0 {
2876 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2877 }
2878 size := t.Size()
2879 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2880 off += size
2881 }
2882 off = Rnd(off, int64(Widthptr))
2883
2884 // Issue call
2885 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2886 s.vars[&memVar] = call
2887
2888 // Finish block
2889 b := s.endBlock()
2890 if !returns {
2891 b.Kind = ssa.BlockExit
Keith Randall56e0ecc2016-03-15 20:45:50 -07002892 b.SetControl(call)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002893 call.AuxInt = off
2894 if len(results) > 0 {
2895 Fatalf("panic call can't have results")
2896 }
2897 return nil
2898 }
2899 b.Kind = ssa.BlockCall
Keith Randall56e0ecc2016-03-15 20:45:50 -07002900 b.SetControl(call)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002901 bNext := s.f.NewBlock(ssa.BlockPlain)
2902 b.AddEdgeTo(bNext)
2903 s.startBlock(bNext)
2904
2905 // Load results
2906 res := make([]*ssa.Value, len(results))
2907 for i, t := range results {
2908 off = Rnd(off, t.Alignment())
2909 ptr := s.sp
2910 if off != 0 {
2911 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2912 }
2913 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2914 off += t.Size()
2915 }
2916 off = Rnd(off, int64(Widthptr))
2917
2918 // Remember how much callee stack space we needed.
2919 call.AuxInt = off
2920
2921 return res
2922}
2923
Keith Randall5ba31942016-01-25 17:06:54 -08002924// insertWBmove inserts the assignment *left = *right including a write barrier.
2925// t is the type being assigned.
2926func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
Keith Randall4304fbc2015-11-16 13:20:16 -08002927 // if writeBarrier.enabled {
Keith Randall5ba31942016-01-25 17:06:54 -08002928 // typedmemmove(&t, left, right)
2929 // } else {
2930 // *left = *right
Keith Randall9d22c102015-09-11 11:02:57 -07002931 // }
Keith Randall15ed37d2016-03-16 21:51:17 -07002932
2933 if s.noWB {
2934 s.Fatalf("write barrier prohibited")
2935 }
2936 if s.WBLineno == 0 {
2937 s.WBLineno = left.Line
2938 }
Keith Randall9d22c102015-09-11 11:02:57 -07002939 bThen := s.f.NewBlock(ssa.BlockPlain)
Keith Randall5ba31942016-01-25 17:06:54 -08002940 bElse := s.f.NewBlock(ssa.BlockPlain)
2941 bEnd := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002942
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002943 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05002944 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002945 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002946 // Load word, test byte, avoiding partial register write from load byte.
2947 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2948 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall9d22c102015-09-11 11:02:57 -07002949 b := s.endBlock()
2950 b.Kind = ssa.BlockIf
2951 b.Likely = ssa.BranchUnlikely
Keith Randall56e0ecc2016-03-15 20:45:50 -07002952 b.SetControl(flag)
Keith Randall9d22c102015-09-11 11:02:57 -07002953 b.AddEdgeTo(bThen)
Keith Randall5ba31942016-01-25 17:06:54 -08002954 b.AddEdgeTo(bElse)
Keith Randall9d22c102015-09-11 11:02:57 -07002955
2956 s.startBlock(bThen)
Keith Randall9d22c102015-09-11 11:02:57 -07002957 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
Keith Randall5ba31942016-01-25 17:06:54 -08002958 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2959 s.endBlock().AddEdgeTo(bEnd)
2960
2961 s.startBlock(bElse)
2962 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2963 s.endBlock().AddEdgeTo(bEnd)
2964
2965 s.startBlock(bEnd)
Keith Randall9d22c102015-09-11 11:02:57 -07002966
David Chase729abfa2015-10-26 17:34:06 -04002967 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002968 Warnl(line, "write barrier")
David Chase729abfa2015-10-26 17:34:06 -04002969 }
Keith Randall5ba31942016-01-25 17:06:54 -08002970}
David Chase729abfa2015-10-26 17:34:06 -04002971
Keith Randall5ba31942016-01-25 17:06:54 -08002972// insertWBstore inserts the assignment *left = right including a write barrier.
2973// t is the type being assigned.
Keith Randalld4663e12016-03-21 10:22:03 -07002974func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32, skip skipMask) {
Keith Randall5ba31942016-01-25 17:06:54 -08002975 // store scalar fields
2976 // if writeBarrier.enabled {
2977 // writebarrierptr for pointer fields
2978 // } else {
2979 // store pointer fields
2980 // }
2981
Keith Randall15ed37d2016-03-16 21:51:17 -07002982 if s.noWB {
2983 s.Fatalf("write barrier prohibited")
2984 }
2985 if s.WBLineno == 0 {
2986 s.WBLineno = left.Line
2987 }
Keith Randalld4663e12016-03-21 10:22:03 -07002988 s.storeTypeScalars(t, left, right, skip)
Keith Randall5ba31942016-01-25 17:06:54 -08002989
2990 bThen := s.f.NewBlock(ssa.BlockPlain)
2991 bElse := s.f.NewBlock(ssa.BlockPlain)
2992 bEnd := s.f.NewBlock(ssa.BlockPlain)
2993
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002994 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05002995 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002996 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002997 // Load word, test byte, avoiding partial register write from load byte.
2998 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2999 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall5ba31942016-01-25 17:06:54 -08003000 b := s.endBlock()
3001 b.Kind = ssa.BlockIf
3002 b.Likely = ssa.BranchUnlikely
Keith Randall56e0ecc2016-03-15 20:45:50 -07003003 b.SetControl(flag)
Keith Randall5ba31942016-01-25 17:06:54 -08003004 b.AddEdgeTo(bThen)
3005 b.AddEdgeTo(bElse)
3006
3007 // Issue write barriers for pointer writes.
3008 s.startBlock(bThen)
Keith Randallaebf6612016-01-29 21:57:57 -08003009 s.storeTypePtrsWB(t, left, right)
3010 s.endBlock().AddEdgeTo(bEnd)
3011
3012 // Issue regular stores for pointer writes.
3013 s.startBlock(bElse)
3014 s.storeTypePtrs(t, left, right)
3015 s.endBlock().AddEdgeTo(bEnd)
3016
3017 s.startBlock(bEnd)
3018
3019 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003020 Warnl(line, "write barrier")
Keith Randallaebf6612016-01-29 21:57:57 -08003021 }
3022}
3023
3024// do *left = right for all scalar (non-pointer) parts of t.
Keith Randalld4663e12016-03-21 10:22:03 -07003025func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value, skip skipMask) {
Keith Randallaebf6612016-01-29 21:57:57 -08003026 switch {
3027 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
3028 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
Matthew Dempsky788f1122016-03-28 10:55:44 -07003029 case t.IsPtrShaped():
Keith Randallaebf6612016-01-29 21:57:57 -08003030 // no scalar fields.
3031 case t.IsString():
Keith Randalld4663e12016-03-21 10:22:03 -07003032 if skip&skipLen != 0 {
3033 return
3034 }
Keith Randallaebf6612016-01-29 21:57:57 -08003035 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
3036 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3037 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3038 case t.IsSlice():
Keith Randalld4663e12016-03-21 10:22:03 -07003039 if skip&skipLen == 0 {
3040 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
3041 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
3042 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
3043 }
3044 if skip&skipCap == 0 {
3045 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
3046 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
3047 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
3048 }
Keith Randallaebf6612016-01-29 21:57:57 -08003049 case t.IsInterface():
3050 // itab field doesn't need a write barrier (even though it is a pointer).
3051 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
3052 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
3053 case t.IsStruct():
3054 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003055 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003056 ft := t.FieldType(i)
3057 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003058 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randalld4663e12016-03-21 10:22:03 -07003059 s.storeTypeScalars(ft.(*Type), addr, val, 0)
Keith Randallaebf6612016-01-29 21:57:57 -08003060 }
3061 default:
3062 s.Fatalf("bad write barrier type %s", t)
3063 }
3064}
3065
3066// do *left = right for all pointer parts of t.
3067func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
3068 switch {
Matthew Dempsky788f1122016-03-28 10:55:44 -07003069 case t.IsPtrShaped():
Keith Randallaebf6612016-01-29 21:57:57 -08003070 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
3071 case t.IsString():
3072 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3073 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3074 case t.IsSlice():
3075 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3076 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
3077 case t.IsInterface():
3078 // itab field is treated as a scalar.
3079 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3080 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3081 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
3082 case t.IsStruct():
3083 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003084 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003085 ft := t.FieldType(i)
3086 if !haspointers(ft.(*Type)) {
3087 continue
3088 }
3089 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003090 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08003091 s.storeTypePtrs(ft.(*Type), addr, val)
3092 }
3093 default:
3094 s.Fatalf("bad write barrier type %s", t)
3095 }
3096}
3097
3098// do *left = right with a write barrier for all pointer parts of t.
3099func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
Keith Randall5ba31942016-01-25 17:06:54 -08003100 switch {
Matthew Dempsky788f1122016-03-28 10:55:44 -07003101 case t.IsPtrShaped():
Keith Randall5ba31942016-01-25 17:06:54 -08003102 s.rtcall(writebarrierptr, true, nil, left, right)
3103 case t.IsString():
3104 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
3105 s.rtcall(writebarrierptr, true, nil, left, ptr)
3106 case t.IsSlice():
3107 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
3108 s.rtcall(writebarrierptr, true, nil, left, ptr)
3109 case t.IsInterface():
3110 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
3111 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
3112 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
Keith Randallaebf6612016-01-29 21:57:57 -08003113 case t.IsStruct():
3114 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003115 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08003116 ft := t.FieldType(i)
3117 if !haspointers(ft.(*Type)) {
3118 continue
3119 }
3120 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003121 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08003122 s.storeTypePtrsWB(ft.(*Type), addr, val)
3123 }
Keith Randall5ba31942016-01-25 17:06:54 -08003124 default:
3125 s.Fatalf("bad write barrier type %s", t)
3126 }
Keith Randall9d22c102015-09-11 11:02:57 -07003127}
3128
Keith Randall5505e8c2015-09-12 23:27:26 -07003129// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
3130// i,j,k may be nil, in which case they are set to their default value.
3131// t is a slice, ptr to array, or string type.
3132func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
3133 var elemtype *Type
3134 var ptrtype *Type
3135 var ptr *ssa.Value
3136 var len *ssa.Value
3137 var cap *ssa.Value
3138 zero := s.constInt(Types[TINT], 0)
3139 switch {
3140 case t.IsSlice():
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003141 elemtype = t.Elem()
Keith Randall5505e8c2015-09-12 23:27:26 -07003142 ptrtype = Ptrto(elemtype)
3143 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
3144 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
3145 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
3146 case t.IsString():
3147 elemtype = Types[TUINT8]
3148 ptrtype = Ptrto(elemtype)
3149 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
3150 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
3151 cap = len
3152 case t.IsPtr():
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003153 if !t.Elem().IsArray() {
Keith Randall5505e8c2015-09-12 23:27:26 -07003154 s.Fatalf("bad ptr to array in slice %v\n", t)
3155 }
Josh Bleecher Snyder8640b512016-03-30 10:57:47 -07003156 elemtype = t.Elem().Elem()
Keith Randall5505e8c2015-09-12 23:27:26 -07003157 ptrtype = Ptrto(elemtype)
3158 s.nilCheck(v)
3159 ptr = v
Josh Bleecher Snyder3a0783c2016-03-31 14:46:04 -07003160 len = s.constInt(Types[TINT], t.Elem().NumElem())
Keith Randall5505e8c2015-09-12 23:27:26 -07003161 cap = len
3162 default:
3163 s.Fatalf("bad type in slice %v\n", t)
3164 }
3165
3166 // Set default values
3167 if i == nil {
3168 i = zero
3169 }
3170 if j == nil {
3171 j = len
3172 }
3173 if k == nil {
3174 k = cap
3175 }
3176
3177 // Panic if slice indices are not in bounds.
3178 s.sliceBoundsCheck(i, j)
3179 if j != k {
3180 s.sliceBoundsCheck(j, k)
3181 }
3182 if k != cap {
3183 s.sliceBoundsCheck(k, cap)
3184 }
3185
3186 // Generate the following code assuming that indexes are in bounds.
3187 // The conditional is to make sure that we don't generate a slice
3188 // that points to the next object in memory.
Keith Randall69a7c1522016-03-21 15:24:08 -07003189 // rlen = j-i
3190 // rcap = k-i
3191 // delta = i*elemsize
3192 // if rcap == 0 {
3193 // delta = 0
Keith Randall5505e8c2015-09-12 23:27:26 -07003194 // }
Keith Randall69a7c1522016-03-21 15:24:08 -07003195 // rptr = p+delta
3196 // result = (SliceMake rptr rlen rcap)
Keith Randall582baae2015-11-02 21:28:13 -08003197 subOp := s.ssaOp(OSUB, Types[TINT])
Keith Randall69a7c1522016-03-21 15:24:08 -07003198 eqOp := s.ssaOp(OEQ, Types[TINT])
Keith Randall582baae2015-11-02 21:28:13 -08003199 mulOp := s.ssaOp(OMUL, Types[TINT])
3200 rlen := s.newValue2(subOp, Types[TINT], j, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003201 var rcap *ssa.Value
3202 switch {
3203 case t.IsString():
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003204 // Capacity of the result is unimportant. However, we use
Keith Randall5505e8c2015-09-12 23:27:26 -07003205 // rcap to test if we've generated a zero-length slice.
3206 // Use length of strings for that.
3207 rcap = rlen
3208 case j == k:
3209 rcap = rlen
3210 default:
Keith Randall582baae2015-11-02 21:28:13 -08003211 rcap = s.newValue2(subOp, Types[TINT], k, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003212 }
3213
Keith Randall69a7c1522016-03-21 15:24:08 -07003214 // delta = # of elements to offset pointer by.
3215 s.vars[&deltaVar] = i
Keith Randall5505e8c2015-09-12 23:27:26 -07003216
Keith Randall69a7c1522016-03-21 15:24:08 -07003217 // Generate code to set delta=0 if the resulting capacity is zero.
3218 if !((i.Op == ssa.OpConst64 && i.AuxInt == 0) ||
3219 (i.Op == ssa.OpConst32 && int32(i.AuxInt) == 0)) {
3220 cmp := s.newValue2(eqOp, Types[TBOOL], rcap, zero)
Keith Randall5505e8c2015-09-12 23:27:26 -07003221
Keith Randall69a7c1522016-03-21 15:24:08 -07003222 b := s.endBlock()
3223 b.Kind = ssa.BlockIf
3224 b.Likely = ssa.BranchUnlikely
3225 b.SetControl(cmp)
Keith Randall5505e8c2015-09-12 23:27:26 -07003226
Keith Randall69a7c1522016-03-21 15:24:08 -07003227 // Generate block which zeros the delta variable.
3228 nz := s.f.NewBlock(ssa.BlockPlain)
3229 b.AddEdgeTo(nz)
3230 s.startBlock(nz)
3231 s.vars[&deltaVar] = zero
3232 s.endBlock()
3233
3234 // All done.
3235 merge := s.f.NewBlock(ssa.BlockPlain)
3236 b.AddEdgeTo(merge)
3237 nz.AddEdgeTo(merge)
3238 s.startBlock(merge)
3239
3240 // TODO: use conditional moves somehow?
Keith Randall5505e8c2015-09-12 23:27:26 -07003241 }
Keith Randall5505e8c2015-09-12 23:27:26 -07003242
Keith Randall69a7c1522016-03-21 15:24:08 -07003243 // Compute rptr = ptr + delta * elemsize
3244 rptr := s.newValue2(ssa.OpAddPtr, ptrtype, ptr, s.newValue2(mulOp, Types[TINT], s.variable(&deltaVar, Types[TINT]), s.constInt(Types[TINT], elemtype.Width)))
3245 delete(s.vars, &deltaVar)
Keith Randall5505e8c2015-09-12 23:27:26 -07003246 return rptr, rlen, rcap
3247}
3248
David Chase42825882015-08-20 15:14:20 -04003249type u2fcvtTab struct {
3250 geq, cvt2F, and, rsh, or, add ssa.Op
3251 one func(*state, ssa.Type, int64) *ssa.Value
3252}
3253
3254var u64_f64 u2fcvtTab = u2fcvtTab{
3255 geq: ssa.OpGeq64,
3256 cvt2F: ssa.OpCvt64to64F,
3257 and: ssa.OpAnd64,
3258 rsh: ssa.OpRsh64Ux64,
3259 or: ssa.OpOr64,
3260 add: ssa.OpAdd64F,
3261 one: (*state).constInt64,
3262}
3263
3264var u64_f32 u2fcvtTab = u2fcvtTab{
3265 geq: ssa.OpGeq64,
3266 cvt2F: ssa.OpCvt64to32F,
3267 and: ssa.OpAnd64,
3268 rsh: ssa.OpRsh64Ux64,
3269 or: ssa.OpOr64,
3270 add: ssa.OpAdd32F,
3271 one: (*state).constInt64,
3272}
3273
3274// Excess generality on a machine with 64-bit integer registers.
3275// Not used on AMD64.
3276var u32_f32 u2fcvtTab = u2fcvtTab{
3277 geq: ssa.OpGeq32,
3278 cvt2F: ssa.OpCvt32to32F,
3279 and: ssa.OpAnd32,
3280 rsh: ssa.OpRsh32Ux32,
3281 or: ssa.OpOr32,
3282 add: ssa.OpAdd32F,
3283 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3284 return s.constInt32(t, int32(x))
3285 },
3286}
3287
3288func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3289 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3290}
3291
3292func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3293 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3294}
3295
3296func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3297 // if x >= 0 {
3298 // result = (floatY) x
3299 // } else {
3300 // y = uintX(x) ; y = x & 1
3301 // z = uintX(x) ; z = z >> 1
3302 // z = z >> 1
3303 // z = z | y
David Chase73151062015-08-26 14:25:40 -04003304 // result = floatY(z)
3305 // result = result + result
David Chase42825882015-08-20 15:14:20 -04003306 // }
3307 //
3308 // Code borrowed from old code generator.
3309 // What's going on: large 64-bit "unsigned" looks like
3310 // negative number to hardware's integer-to-float
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003311 // conversion. However, because the mantissa is only
David Chase42825882015-08-20 15:14:20 -04003312 // 63 bits, we don't need the LSB, so instead we do an
3313 // unsigned right shift (divide by two), convert, and
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003314 // double. However, before we do that, we need to be
David Chase42825882015-08-20 15:14:20 -04003315 // sure that we do not lose a "1" if that made the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003316 // difference in the resulting rounding. Therefore, we
3317 // preserve it, and OR (not ADD) it back in. The case
David Chase42825882015-08-20 15:14:20 -04003318 // that matters is when the eleven discarded bits are
3319 // equal to 10000000001; that rounds up, and the 1 cannot
3320 // be lost else it would round down if the LSB of the
3321 // candidate mantissa is 0.
3322 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3323 b := s.endBlock()
3324 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003325 b.SetControl(cmp)
David Chase42825882015-08-20 15:14:20 -04003326 b.Likely = ssa.BranchLikely
3327
3328 bThen := s.f.NewBlock(ssa.BlockPlain)
3329 bElse := s.f.NewBlock(ssa.BlockPlain)
3330 bAfter := s.f.NewBlock(ssa.BlockPlain)
3331
Todd Neal47d67992015-08-28 21:36:29 -05003332 b.AddEdgeTo(bThen)
David Chase42825882015-08-20 15:14:20 -04003333 s.startBlock(bThen)
3334 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3335 s.vars[n] = a0
3336 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003337 bThen.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003338
Todd Neal47d67992015-08-28 21:36:29 -05003339 b.AddEdgeTo(bElse)
David Chase42825882015-08-20 15:14:20 -04003340 s.startBlock(bElse)
3341 one := cvttab.one(s, ft, 1)
3342 y := s.newValue2(cvttab.and, ft, x, one)
3343 z := s.newValue2(cvttab.rsh, ft, x, one)
3344 z = s.newValue2(cvttab.or, ft, z, y)
3345 a := s.newValue1(cvttab.cvt2F, tt, z)
3346 a1 := s.newValue2(cvttab.add, tt, a, a)
3347 s.vars[n] = a1
3348 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003349 bElse.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003350
3351 s.startBlock(bAfter)
3352 return s.variable(n, n.Type)
3353}
3354
Todd Neal707af252015-08-28 15:56:43 -05003355// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3356func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3357 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3358 s.Fatalf("node must be a map or a channel")
3359 }
Todd Neale0e40682015-08-26 18:40:52 -05003360 // if n == nil {
3361 // return 0
3362 // } else {
Todd Neal707af252015-08-28 15:56:43 -05003363 // // len
Todd Neale0e40682015-08-26 18:40:52 -05003364 // return *((*int)n)
Todd Neal707af252015-08-28 15:56:43 -05003365 // // cap
3366 // return *(((*int)n)+1)
Todd Neale0e40682015-08-26 18:40:52 -05003367 // }
3368 lenType := n.Type
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003369 nilValue := s.constNil(Types[TUINTPTR])
Todd Neal67ac8a32015-08-28 15:20:54 -05003370 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
Todd Neale0e40682015-08-26 18:40:52 -05003371 b := s.endBlock()
3372 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003373 b.SetControl(cmp)
Todd Neale0e40682015-08-26 18:40:52 -05003374 b.Likely = ssa.BranchUnlikely
3375
3376 bThen := s.f.NewBlock(ssa.BlockPlain)
3377 bElse := s.f.NewBlock(ssa.BlockPlain)
3378 bAfter := s.f.NewBlock(ssa.BlockPlain)
3379
Todd Neal707af252015-08-28 15:56:43 -05003380 // length/capacity of a nil map/chan is zero
Todd Neal47d67992015-08-28 21:36:29 -05003381 b.AddEdgeTo(bThen)
Todd Neale0e40682015-08-26 18:40:52 -05003382 s.startBlock(bThen)
3383 s.vars[n] = s.zeroVal(lenType)
3384 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003385 bThen.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003386
Todd Neal47d67992015-08-28 21:36:29 -05003387 b.AddEdgeTo(bElse)
Todd Neale0e40682015-08-26 18:40:52 -05003388 s.startBlock(bElse)
Todd Neal707af252015-08-28 15:56:43 -05003389 if n.Op == OLEN {
3390 // length is stored in the first word for map/chan
3391 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3392 } else if n.Op == OCAP {
3393 // capacity is stored in the second word for chan
3394 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3395 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3396 } else {
3397 s.Fatalf("op must be OLEN or OCAP")
3398 }
Todd Neale0e40682015-08-26 18:40:52 -05003399 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003400 bElse.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003401
3402 s.startBlock(bAfter)
3403 return s.variable(n, lenType)
3404}
3405
David Chase73151062015-08-26 14:25:40 -04003406type f2uCvtTab struct {
3407 ltf, cvt2U, subf ssa.Op
3408 value func(*state, ssa.Type, float64) *ssa.Value
3409}
3410
3411var f32_u64 f2uCvtTab = f2uCvtTab{
3412 ltf: ssa.OpLess32F,
3413 cvt2U: ssa.OpCvt32Fto64,
3414 subf: ssa.OpSub32F,
3415 value: (*state).constFloat32,
3416}
3417
3418var f64_u64 f2uCvtTab = f2uCvtTab{
3419 ltf: ssa.OpLess64F,
3420 cvt2U: ssa.OpCvt64Fto64,
3421 subf: ssa.OpSub64F,
3422 value: (*state).constFloat64,
3423}
3424
3425func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3426 return s.floatToUint(&f32_u64, n, x, ft, tt)
3427}
3428func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3429 return s.floatToUint(&f64_u64, n, x, ft, tt)
3430}
3431
3432func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3433 // if x < 9223372036854775808.0 {
3434 // result = uintY(x)
3435 // } else {
3436 // y = x - 9223372036854775808.0
3437 // z = uintY(y)
3438 // result = z | -9223372036854775808
3439 // }
3440 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3441 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3442 b := s.endBlock()
3443 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003444 b.SetControl(cmp)
David Chase73151062015-08-26 14:25:40 -04003445 b.Likely = ssa.BranchLikely
3446
3447 bThen := s.f.NewBlock(ssa.BlockPlain)
3448 bElse := s.f.NewBlock(ssa.BlockPlain)
3449 bAfter := s.f.NewBlock(ssa.BlockPlain)
3450
Todd Neal47d67992015-08-28 21:36:29 -05003451 b.AddEdgeTo(bThen)
David Chase73151062015-08-26 14:25:40 -04003452 s.startBlock(bThen)
3453 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3454 s.vars[n] = a0
3455 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003456 bThen.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003457
Todd Neal47d67992015-08-28 21:36:29 -05003458 b.AddEdgeTo(bElse)
David Chase73151062015-08-26 14:25:40 -04003459 s.startBlock(bElse)
3460 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3461 y = s.newValue1(cvttab.cvt2U, tt, y)
3462 z := s.constInt64(tt, -9223372036854775808)
3463 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3464 s.vars[n] = a1
3465 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003466 bElse.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003467
3468 s.startBlock(bAfter)
3469 return s.variable(n, n.Type)
3470}
3471
Keith Randall269baa92015-09-17 10:31:16 -07003472// ifaceType returns the value for the word containing the type.
3473// n is the node for the interface expression.
3474// v is the corresponding value.
3475func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3476 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3477
Matthew Dempsky00e5a682016-04-01 13:36:24 -07003478 if n.Type.IsEmptyInterface() {
Keith Randall269baa92015-09-17 10:31:16 -07003479 // Have *eface. The type is the first word in the struct.
3480 return s.newValue1(ssa.OpITab, byteptr, v)
3481 }
3482
3483 // Have *iface.
3484 // The first word in the struct is the *itab.
3485 // If the *itab is nil, return 0.
3486 // Otherwise, the second word in the *itab is the type.
3487
3488 tab := s.newValue1(ssa.OpITab, byteptr, v)
3489 s.vars[&typVar] = tab
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003490 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
Keith Randall269baa92015-09-17 10:31:16 -07003491 b := s.endBlock()
3492 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003493 b.SetControl(isnonnil)
Keith Randall269baa92015-09-17 10:31:16 -07003494 b.Likely = ssa.BranchLikely
3495
3496 bLoad := s.f.NewBlock(ssa.BlockPlain)
3497 bEnd := s.f.NewBlock(ssa.BlockPlain)
3498
3499 b.AddEdgeTo(bLoad)
3500 b.AddEdgeTo(bEnd)
3501 bLoad.AddEdgeTo(bEnd)
3502
3503 s.startBlock(bLoad)
3504 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3505 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3506 s.endBlock()
3507
3508 s.startBlock(bEnd)
3509 typ := s.variable(&typVar, byteptr)
3510 delete(s.vars, &typVar)
3511 return typ
3512}
3513
3514// dottype generates SSA for a type assertion node.
3515// commaok indicates whether to panic or return a bool.
3516// If commaok is false, resok will be nil.
3517func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3518 iface := s.expr(n.Left)
3519 typ := s.ifaceType(n.Left, iface) // actual concrete type
3520 target := s.expr(typename(n.Type)) // target type
3521 if !isdirectiface(n.Type) {
3522 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3523 Fatalf("dottype needs a direct iface type %s", n.Type)
3524 }
3525
David Chase729abfa2015-10-26 17:34:06 -04003526 if Debug_typeassert > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003527 Warnl(n.Lineno, "type assertion inlined")
David Chase729abfa2015-10-26 17:34:06 -04003528 }
3529
Keith Randall269baa92015-09-17 10:31:16 -07003530 // TODO: If we have a nonempty interface and its itab field is nil,
3531 // then this test is redundant and ifaceType should just branch directly to bFail.
3532 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3533 b := s.endBlock()
3534 b.Kind = ssa.BlockIf
Keith Randall56e0ecc2016-03-15 20:45:50 -07003535 b.SetControl(cond)
Keith Randall269baa92015-09-17 10:31:16 -07003536 b.Likely = ssa.BranchLikely
3537
3538 byteptr := Ptrto(Types[TUINT8])
3539
3540 bOk := s.f.NewBlock(ssa.BlockPlain)
3541 bFail := s.f.NewBlock(ssa.BlockPlain)
3542 b.AddEdgeTo(bOk)
3543 b.AddEdgeTo(bFail)
3544
3545 if !commaok {
3546 // on failure, panic by calling panicdottype
3547 s.startBlock(bFail)
Keith Randall269baa92015-09-17 10:31:16 -07003548 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07003549 s.rtcall(panicdottype, false, nil, typ, target, taddr)
Keith Randall269baa92015-09-17 10:31:16 -07003550
3551 // on success, return idata field
3552 s.startBlock(bOk)
3553 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3554 }
3555
3556 // commaok is the more complicated case because we have
3557 // a control flow merge point.
3558 bEnd := s.f.NewBlock(ssa.BlockPlain)
3559
3560 // type assertion succeeded
3561 s.startBlock(bOk)
3562 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3563 s.vars[&okVar] = s.constBool(true)
3564 s.endBlock()
3565 bOk.AddEdgeTo(bEnd)
3566
3567 // type assertion failed
3568 s.startBlock(bFail)
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003569 s.vars[&idataVar] = s.constNil(byteptr)
Keith Randall269baa92015-09-17 10:31:16 -07003570 s.vars[&okVar] = s.constBool(false)
3571 s.endBlock()
3572 bFail.AddEdgeTo(bEnd)
3573
3574 // merge point
3575 s.startBlock(bEnd)
3576 res = s.variable(&idataVar, byteptr)
3577 resok = s.variable(&okVar, Types[TBOOL])
3578 delete(s.vars, &idataVar)
3579 delete(s.vars, &okVar)
3580 return res, resok
3581}
3582
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003583// checkgoto checks that a goto from from to to does not
3584// jump into a block or jump over variable declarations.
3585// It is a copy of checkgoto in the pre-SSA backend,
3586// modified only for line number handling.
3587// TODO: document how this works and why it is designed the way it is.
3588func (s *state) checkgoto(from *Node, to *Node) {
3589 if from.Sym == to.Sym {
3590 return
3591 }
3592
3593 nf := 0
3594 for fs := from.Sym; fs != nil; fs = fs.Link {
3595 nf++
3596 }
3597 nt := 0
3598 for fs := to.Sym; fs != nil; fs = fs.Link {
3599 nt++
3600 }
3601 fs := from.Sym
3602 for ; nf > nt; nf-- {
3603 fs = fs.Link
3604 }
3605 if fs != to.Sym {
3606 // decide what to complain about.
3607 // prefer to complain about 'into block' over declarations,
3608 // so scan backward to find most recent block or else dcl.
3609 var block *Sym
3610
3611 var dcl *Sym
3612 ts := to.Sym
3613 for ; nt > nf; nt-- {
3614 if ts.Pkg == nil {
3615 block = ts
3616 } else {
3617 dcl = ts
3618 }
3619 ts = ts.Link
3620 }
3621
3622 for ts != fs {
3623 if ts.Pkg == nil {
3624 block = ts
3625 } else {
3626 dcl = ts
3627 }
3628 ts = ts.Link
3629 fs = fs.Link
3630 }
3631
Robert Griesemerb83f3972016-03-02 11:01:25 -08003632 lno := from.Left.Lineno
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003633 if block != nil {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003634 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003635 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003636 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 -07003637 }
3638 }
3639}
3640
Keith Randalld2fd43a2015-04-15 15:51:25 -07003641// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -07003642func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003643 v := s.vars[name]
3644 if v == nil {
Keith Randall8f22b522015-06-11 21:29:25 -07003645 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randallb5c5efd2016-01-14 16:02:23 -08003646 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003647 s.vars[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003648 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003649 }
3650 return v
3651}
3652
Keith Randallcfc2aa52015-05-18 16:44:20 -07003653func (s *state) mem() *ssa.Value {
Keith Randallb32217a2015-09-17 16:45:10 -07003654 return s.variable(&memVar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003655}
3656
Keith Randallcfc2aa52015-05-18 16:44:20 -07003657func (s *state) linkForwardReferences() {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003658 // Build SSA graph. Each variable on its first use in a basic block
Keith Randalld2fd43a2015-04-15 15:51:25 -07003659 // leaves a FwdRef in that block representing the incoming value
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003660 // of that variable. This function links that ref up with possible definitions,
3661 // inserting Phi values as needed. This is essentially the algorithm
Keith Randallb5c5efd2016-01-14 16:02:23 -08003662 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
Keith Randalld2fd43a2015-04-15 15:51:25 -07003663 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
Keith Randallb5c5efd2016-01-14 16:02:23 -08003664 // Differences:
3665 // - We use FwdRef nodes to postpone phi building until the CFG is
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003666 // completely built. That way we can avoid the notion of "sealed"
Keith Randallb5c5efd2016-01-14 16:02:23 -08003667 // blocks.
3668 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3669 for len(s.fwdRefs) > 0 {
3670 v := s.fwdRefs[len(s.fwdRefs)-1]
3671 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3672 s.resolveFwdRef(v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003673 }
3674}
3675
Keith Randallb5c5efd2016-01-14 16:02:23 -08003676// resolveFwdRef modifies v to be the variable's value at the start of its block.
3677// v must be a FwdRef op.
3678func (s *state) resolveFwdRef(v *ssa.Value) {
3679 b := v.Block
3680 name := v.Aux.(*Node)
3681 v.Aux = nil
Keith Randalld2fd43a2015-04-15 15:51:25 -07003682 if b == s.f.Entry {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003683 // Live variable at start of function.
Keith Randall6a8a9da2016-02-27 17:49:31 -08003684 if s.canSSA(name) {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003685 v.Op = ssa.OpArg
3686 v.Aux = name
3687 return
Keith Randall02f4d0a2015-11-02 08:10:26 -08003688 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003689 // Not SSAable. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -07003690 addr := s.decladdrs[name]
3691 if addr == nil {
3692 // TODO: closure args reach here.
David Chase32ffbf72015-10-08 17:14:12 -04003693 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
Keith Randall8c46aa52015-06-19 21:02:28 -07003694 }
3695 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3696 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3697 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003698 v.Op = ssa.OpLoad
3699 v.AddArgs(addr, s.startmem)
3700 return
Keith Randalld2fd43a2015-04-15 15:51:25 -07003701 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003702 if len(b.Preds) == 0 {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003703 // This block is dead; we have no predecessors and we're not the entry block.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003704 // It doesn't matter what we use here as long as it is well-formed.
3705 v.Op = ssa.OpUnknown
3706 return
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003707 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003708 // Find variable value on each predecessor.
3709 var argstore [4]*ssa.Value
3710 args := argstore[:0]
3711 for _, p := range b.Preds {
3712 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
Keith Randalld2fd43a2015-04-15 15:51:25 -07003713 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003714
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003715 // Decide if we need a phi or not. We need a phi if there
Keith Randallb5c5efd2016-01-14 16:02:23 -08003716 // are two different args (which are both not v).
3717 var w *ssa.Value
3718 for _, a := range args {
3719 if a == v {
3720 continue // self-reference
3721 }
3722 if a == w {
3723 continue // already have this witness
3724 }
3725 if w != nil {
3726 // two witnesses, need a phi value
3727 v.Op = ssa.OpPhi
3728 v.AddArgs(args...)
3729 return
3730 }
3731 w = a // save witness
3732 }
3733 if w == nil {
3734 s.Fatalf("no witness for reachable phi %s", v)
3735 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003736 // One witness. Make v a copy of w.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003737 v.Op = ssa.OpCopy
3738 v.AddArg(w)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003739}
3740
3741// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003742func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003743 m := s.defvars[b.ID]
3744 if v, ok := m[name]; ok {
3745 return v
3746 }
3747 // The variable is not defined by b and we haven't
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003748 // looked it up yet. Generate a FwdRef for the variable and return that.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003749 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3750 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003751 m[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003752 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003753 return v
3754}
3755
Keith Randallc24681a2015-10-22 14:22:38 -07003756func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3757 if n.Class == Pxxx {
3758 // Don't track our dummy nodes (&memVar etc.).
3759 return
3760 }
Keith Randallc24681a2015-10-22 14:22:38 -07003761 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3762 // Don't track autotmp_ variables.
3763 return
3764 }
Keith Randall31d13f42016-03-08 20:09:48 -08003765 if n.Class == PPARAMOUT {
3766 // Don't track named output values. This prevents return values
3767 // from being assigned too early. See #14591 and #14762. TODO: allow this.
3768 return
3769 }
Keith Randallc24681a2015-10-22 14:22:38 -07003770 if n.Class == PAUTO && n.Xoffset != 0 {
3771 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3772 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003773 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3774 values, ok := s.f.NamedValues[loc]
Keith Randallc24681a2015-10-22 14:22:38 -07003775 if !ok {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003776 s.f.Names = append(s.f.Names, loc)
Keith Randallc24681a2015-10-22 14:22:38 -07003777 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003778 s.f.NamedValues[loc] = append(values, v)
Keith Randallc24681a2015-10-22 14:22:38 -07003779}
3780
Michael Pratta4e31d42016-03-12 14:07:40 -08003781// Branch is an unresolved branch.
3782type Branch struct {
3783 P *obj.Prog // branch instruction
3784 B *ssa.Block // target
Keith Randall083a6462015-05-12 11:06:44 -07003785}
3786
Michael Pratta4e31d42016-03-12 14:07:40 -08003787// SSAGenState contains state needed during Prog generation.
3788type SSAGenState struct {
3789 // Branches remembers all the branch instructions we've seen
Keith Randall9569b952015-08-28 22:51:01 -07003790 // and where they would like to go.
Michael Pratta4e31d42016-03-12 14:07:40 -08003791 Branches []Branch
Keith Randall9569b952015-08-28 22:51:01 -07003792
3793 // bstart remembers where each block starts (indexed by block ID)
3794 bstart []*obj.Prog
Keith Randall9569b952015-08-28 22:51:01 -07003795}
3796
Michael Pratta4e31d42016-03-12 14:07:40 -08003797// Pc returns the current Prog.
3798func (s *SSAGenState) Pc() *obj.Prog {
3799 return Pc
3800}
3801
3802// SetLineno sets the current source line number.
3803func (s *SSAGenState) SetLineno(l int32) {
3804 lineno = l
3805}
3806
Keith Randall083a6462015-05-12 11:06:44 -07003807// genssa appends entries to ptxt for each instruction in f.
3808// gcargs and gclocals are filled in with pointer maps for the frame.
3809func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Michael Pratta4e31d42016-03-12 14:07:40 -08003810 var s SSAGenState
Keith Randall9569b952015-08-28 22:51:01 -07003811
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003812 e := f.Config.Frontend().(*ssaExport)
3813 // We're about to emit a bunch of Progs.
3814 // Since the only way to get here is to explicitly request it,
3815 // just fail on unimplemented instead of trying to unwind our mess.
3816 e.mustImplement = true
3817
Keith Randall083a6462015-05-12 11:06:44 -07003818 // Remember where each block starts.
Keith Randall9569b952015-08-28 22:51:01 -07003819 s.bstart = make([]*obj.Prog, f.NumBlocks())
Keith Randall083a6462015-05-12 11:06:44 -07003820
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003821 var valueProgs map[*obj.Prog]*ssa.Value
3822 var blockProgs map[*obj.Prog]*ssa.Block
Dave Cheneycb1f2af2016-03-17 13:46:43 +11003823 var logProgs = e.log
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003824 if logProgs {
3825 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3826 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3827 f.Logf("genssa %s\n", f.Name)
3828 blockProgs[Pc] = f.Blocks[0]
3829 }
3830
Keith Randall083a6462015-05-12 11:06:44 -07003831 // Emit basic blocks
3832 for i, b := range f.Blocks {
Keith Randall9569b952015-08-28 22:51:01 -07003833 s.bstart[b.ID] = Pc
Keith Randall083a6462015-05-12 11:06:44 -07003834 // Emit values in block
Michael Pratta4e31d42016-03-12 14:07:40 -08003835 Thearch.SSAMarkMoves(&s, b)
Keith Randall083a6462015-05-12 11:06:44 -07003836 for _, v := range b.Values {
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003837 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003838 Thearch.SSAGenValue(&s, v)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003839 if logProgs {
3840 for ; x != Pc; x = x.Link {
3841 valueProgs[x] = v
3842 }
3843 }
Keith Randall083a6462015-05-12 11:06:44 -07003844 }
3845 // Emit control flow instructions for block
3846 var next *ssa.Block
Keith Randall91f69c62016-02-26 16:32:01 -08003847 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
Keith Randall8906d2a2016-02-22 23:19:00 -08003848 // If -N, leave next==nil so every block with successors
Keith Randall91f69c62016-02-26 16:32:01 -08003849 // ends in a JMP (except call blocks - plive doesn't like
3850 // select{send,recv} followed by a JMP call). Helps keep
3851 // line numbers for otherwise empty blocks.
Keith Randall083a6462015-05-12 11:06:44 -07003852 next = f.Blocks[i+1]
3853 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003854 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003855 Thearch.SSAGenBlock(&s, b, next)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003856 if logProgs {
3857 for ; x != Pc; x = x.Link {
3858 blockProgs[x] = b
3859 }
3860 }
Keith Randall083a6462015-05-12 11:06:44 -07003861 }
3862
3863 // Resolve branches
Michael Pratta4e31d42016-03-12 14:07:40 -08003864 for _, br := range s.Branches {
3865 br.P.To.Val = s.bstart[br.B.ID]
Keith Randall9569b952015-08-28 22:51:01 -07003866 }
Keith Randall083a6462015-05-12 11:06:44 -07003867
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003868 if logProgs {
3869 for p := ptxt; p != nil; p = p.Link {
3870 var s string
3871 if v, ok := valueProgs[p]; ok {
3872 s = v.String()
3873 } else if b, ok := blockProgs[p]; ok {
3874 s = b.String()
3875 } else {
3876 s = " " // most value and branch strings are 2-3 characters long
3877 }
3878 f.Logf("%s\t%s\n", s, p)
3879 }
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003880 if f.Config.HTML != nil {
3881 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3882 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3883 var buf bytes.Buffer
3884 buf.WriteString("<code>")
3885 buf.WriteString("<dl class=\"ssa-gen\">")
3886 for p := ptxt; p != nil; p = p.Link {
3887 buf.WriteString("<dt class=\"ssa-prog-src\">")
3888 if v, ok := valueProgs[p]; ok {
3889 buf.WriteString(v.HTML())
3890 } else if b, ok := blockProgs[p]; ok {
3891 buf.WriteString(b.HTML())
3892 }
3893 buf.WriteString("</dt>")
3894 buf.WriteString("<dd class=\"ssa-prog\">")
3895 buf.WriteString(html.EscapeString(p.String()))
3896 buf.WriteString("</dd>")
3897 buf.WriteString("</li>")
3898 }
3899 buf.WriteString("</dl>")
3900 buf.WriteString("</code>")
3901 f.Config.HTML.WriteColumn("genssa", buf.String())
3902 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3903 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003904 }
3905
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003906 // Emit static data
3907 if f.StaticData != nil {
3908 for _, n := range f.StaticData.([]*Node) {
3909 if !gen_as_init(n, false) {
Keith Randall0ec72b62015-09-08 15:42:53 -07003910 Fatalf("non-static data marked as static: %v\n\n", n, f)
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003911 }
3912 }
3913 }
3914
Keith Randalld2107fc2015-08-24 02:16:19 -07003915 // Allocate stack frame
3916 allocauto(ptxt)
Keith Randall083a6462015-05-12 11:06:44 -07003917
Keith Randalld2107fc2015-08-24 02:16:19 -07003918 // Generate gc bitmaps.
3919 liveness(Curfn, ptxt, gcargs, gclocals)
3920 gcsymdup(gcargs)
3921 gcsymdup(gclocals)
Keith Randall083a6462015-05-12 11:06:44 -07003922
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003923 // Add frame prologue. Zero ambiguously live variables.
Keith Randalld2107fc2015-08-24 02:16:19 -07003924 Thearch.Defframe(ptxt)
3925 if Debug['f'] != 0 {
3926 frame(0)
3927 }
3928
3929 // Remove leftover instrumentation from the instruction stream.
3930 removevardef(ptxt)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003931
3932 f.Config.HTML.Close()
Keith Randall083a6462015-05-12 11:06:44 -07003933}
3934
Daniel Morsing66b47812015-06-27 15:45:20 +01003935// 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 -08003936func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
Daniel Morsing66b47812015-06-27 15:45:20 +01003937 p := Prog(as)
3938 // TODO: use zero register on archs that support it.
3939 p.From.Type = obj.TYPE_CONST
3940 p.From.Offset = 0
3941 p.To.Type = obj.TYPE_MEM
3942 p.To.Reg = regnum
3943 p.To.Offset = offset
3944 offset += width
3945 nleft = nbytes - width
3946 return nleft, offset
3947}
3948
Michael Pratta4e31d42016-03-12 14:07:40 -08003949type FloatingEQNEJump struct {
3950 Jump obj.As
3951 Index int
David Chase8e601b22015-08-18 14:39:26 -04003952}
3953
Michael Pratta4e31d42016-03-12 14:07:40 -08003954func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
3955 p := Prog(jumps.Jump)
David Chase8e601b22015-08-18 14:39:26 -04003956 p.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08003957 to := jumps.Index
3958 branches = append(branches, Branch{p, b.Succs[to]})
David Chase8e601b22015-08-18 14:39:26 -04003959 if to == 1 {
3960 likely = -likely
3961 }
3962 // liblink reorders the instruction stream as it sees fit.
3963 // Pass along what we know so liblink can make use of it.
3964 // TODO: Once we've fully switched to SSA,
3965 // make liblink leave our output alone.
3966 switch likely {
3967 case ssa.BranchUnlikely:
3968 p.From.Type = obj.TYPE_CONST
3969 p.From.Offset = 0
3970 case ssa.BranchLikely:
3971 p.From.Type = obj.TYPE_CONST
3972 p.From.Offset = 1
3973 }
3974 return branches
3975}
3976
Michael Pratta4e31d42016-03-12 14:07:40 -08003977func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
David Chase8e601b22015-08-18 14:39:26 -04003978 likely := b.Likely
3979 switch next {
3980 case b.Succs[0]:
Michael Pratta4e31d42016-03-12 14:07:40 -08003981 s.Branches = oneFPJump(b, &jumps[0][0], likely, s.Branches)
3982 s.Branches = oneFPJump(b, &jumps[0][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003983 case b.Succs[1]:
Michael Pratta4e31d42016-03-12 14:07:40 -08003984 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
3985 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003986 default:
Michael Pratta4e31d42016-03-12 14:07:40 -08003987 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
3988 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003989 q := Prog(obj.AJMP)
3990 q.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08003991 s.Branches = append(s.Branches, Branch{q, b.Succs[1]})
David Chase8e601b22015-08-18 14:39:26 -04003992 }
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07003993}
3994
Michael Pratta4e31d42016-03-12 14:07:40 -08003995// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
3996func AddAux(a *obj.Addr, v *ssa.Value) {
3997 AddAux2(a, v, v.AuxInt)
Keith Randall083a6462015-05-12 11:06:44 -07003998}
Michael Pratta4e31d42016-03-12 14:07:40 -08003999func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
Keith Randall8c46aa52015-06-19 21:02:28 -07004000 if a.Type != obj.TYPE_MEM {
Michael Pratta4e31d42016-03-12 14:07:40 -08004001 v.Fatalf("bad AddAux addr %s", a)
Keith Randall8c46aa52015-06-19 21:02:28 -07004002 }
4003 // add integer offset
Keith Randalld43f2e32015-10-21 13:13:56 -07004004 a.Offset += offset
Keith Randall8c46aa52015-06-19 21:02:28 -07004005
4006 // If no additional symbol offset, we're done.
4007 if v.Aux == nil {
4008 return
4009 }
4010 // Add symbol's offset from its base register.
4011 switch sym := v.Aux.(type) {
4012 case *ssa.ExternSymbol:
4013 a.Name = obj.NAME_EXTERN
Ian Lance Taylor65b40202016-03-16 22:22:58 -07004014 switch s := sym.Sym.(type) {
4015 case *Sym:
4016 a.Sym = Linksym(s)
4017 case *obj.LSym:
4018 a.Sym = s
4019 default:
4020 v.Fatalf("ExternSymbol.Sym is %T", s)
4021 }
Keith Randall8c46aa52015-06-19 21:02:28 -07004022 case *ssa.ArgSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004023 n := sym.Node.(*Node)
4024 a.Name = obj.NAME_PARAM
4025 a.Node = n
4026 a.Sym = Linksym(n.Orig.Sym)
4027 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 -07004028 case *ssa.AutoSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004029 n := sym.Node.(*Node)
4030 a.Name = obj.NAME_AUTO
4031 a.Node = n
4032 a.Sym = Linksym(n.Sym)
Keith Randall8c46aa52015-06-19 21:02:28 -07004033 default:
4034 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4035 }
4036}
4037
Keith Randall582baae2015-11-02 21:28:13 -08004038// extendIndex extends v to a full int width.
Keith Randall2a5e6c42015-07-23 14:35:02 -07004039func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4040 size := v.Type.Size()
Keith Randall582baae2015-11-02 21:28:13 -08004041 if size == s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004042 return v
4043 }
Keith Randall582baae2015-11-02 21:28:13 -08004044 if size > s.config.IntSize {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004045 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
Keith Randall2a5e6c42015-07-23 14:35:02 -07004046 // the high word and branch to out-of-bounds failure if it is not 0.
4047 s.Unimplementedf("64->32 index truncation not implemented")
4048 return v
4049 }
4050
4051 // Extend value to the required size
4052 var op ssa.Op
4053 if v.Type.IsSigned() {
Keith Randall582baae2015-11-02 21:28:13 -08004054 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004055 case 14:
4056 op = ssa.OpSignExt8to32
4057 case 18:
4058 op = ssa.OpSignExt8to64
4059 case 24:
4060 op = ssa.OpSignExt16to32
4061 case 28:
4062 op = ssa.OpSignExt16to64
4063 case 48:
4064 op = ssa.OpSignExt32to64
4065 default:
4066 s.Fatalf("bad signed index extension %s", v.Type)
4067 }
4068 } else {
Keith Randall582baae2015-11-02 21:28:13 -08004069 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004070 case 14:
4071 op = ssa.OpZeroExt8to32
4072 case 18:
4073 op = ssa.OpZeroExt8to64
4074 case 24:
4075 op = ssa.OpZeroExt16to32
4076 case 28:
4077 op = ssa.OpZeroExt16to64
4078 case 48:
4079 op = ssa.OpZeroExt32to64
4080 default:
4081 s.Fatalf("bad unsigned index extension %s", v.Type)
4082 }
4083 }
Keith Randall582baae2015-11-02 21:28:13 -08004084 return s.newValue1(op, Types[TINT], v)
Keith Randall2a5e6c42015-07-23 14:35:02 -07004085}
4086
Michael Pratta4e31d42016-03-12 14:07:40 -08004087// SSARegNum returns the register (in cmd/internal/obj numbering) to
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00004088// which v has been allocated. Panics if v is not assigned to a
Keith Randall083a6462015-05-12 11:06:44 -07004089// register.
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004090// TODO: Make this panic again once it stops happening routinely.
Michael Pratta4e31d42016-03-12 14:07:40 -08004091func SSARegNum(v *ssa.Value) int16 {
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004092 reg := v.Block.Func.RegAlloc[v.ID]
4093 if reg == nil {
4094 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
4095 return 0
4096 }
Michael Pratta4e31d42016-03-12 14:07:40 -08004097 return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
Keith Randall083a6462015-05-12 11:06:44 -07004098}
4099
Michael Pratta4e31d42016-03-12 14:07:40 -08004100// AutoVar returns a *Node and int64 representing the auto variable and offset within it
Keith Randall02f4d0a2015-11-02 08:10:26 -08004101// where v should be spilled.
Michael Pratta4e31d42016-03-12 14:07:40 -08004102func AutoVar(v *ssa.Value) (*Node, int64) {
Keith Randall02f4d0a2015-11-02 08:10:26 -08004103 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
Keith Randall9094e3a2016-01-04 13:34:54 -08004104 if v.Type.Size() > loc.Type.Size() {
4105 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
4106 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08004107 return loc.N.(*Node), loc.Off
Keith Randall083a6462015-05-12 11:06:44 -07004108}
Keith Randallf7f604e2015-05-27 14:52:22 -07004109
Keith Randalla734bbc2016-01-11 21:05:33 -08004110// fieldIdx finds the index of the field referred to by the ODOT node n.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07004111func fieldIdx(n *Node) int {
Keith Randalla734bbc2016-01-11 21:05:33 -08004112 t := n.Left.Type
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07004113 f := n.Sym
Matthew Dempsky3efefd92016-03-30 14:56:08 -07004114 if !t.IsStruct() {
Keith Randalla734bbc2016-01-11 21:05:33 -08004115 panic("ODOT's LHS is not a struct")
4116 }
4117
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07004118 var i int
Matthew Dempskyf6bca3f2016-03-17 01:32:18 -07004119 for _, t1 := range t.Fields().Slice() {
Ian Lance Taylor5f525ca2016-03-18 16:52:30 -07004120 if t1.Sym != f {
Keith Randalla734bbc2016-01-11 21:05:33 -08004121 i++
4122 continue
4123 }
Matthew Dempsky62dddd42016-03-28 09:40:53 -07004124 if t1.Offset != n.Xoffset {
Keith Randalla734bbc2016-01-11 21:05:33 -08004125 panic("field offset doesn't match")
4126 }
4127 return i
4128 }
4129 panic(fmt.Sprintf("can't find field in expr %s\n", n))
4130
Eric Engestrom7a8caf72016-04-03 12:43:27 +01004131 // TODO: keep the result of this function somewhere in the ODOT Node
Keith Randalla734bbc2016-01-11 21:05:33 -08004132 // so we don't have to recompute it each time we need it.
4133}
4134
Keith Randallf7f604e2015-05-27 14:52:22 -07004135// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004136type ssaExport struct {
4137 log bool
4138 unimplemented bool
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004139 mustImplement bool
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004140}
Keith Randallf7f604e2015-05-27 14:52:22 -07004141
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004142func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
4143func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
4144func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
4145func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
4146func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
4147func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
4148func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
4149func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
4150func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
David Chase52578582015-08-28 14:24:10 -04004151func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
4152func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004153func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
4154func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
4155func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
4156func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
4157
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004158// StringData returns a symbol (a *Sym wrapped in an interface) which
4159// is the data component of a global string constant containing s.
4160func (*ssaExport) StringData(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07004161 // TODO: is idealstring correct? It might not matter...
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004162 _, data := stringsym(s)
4163 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
Keith Randallf7f604e2015-05-27 14:52:22 -07004164}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004165
Keith Randallc24681a2015-10-22 14:22:38 -07004166func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
Keith Randalld2107fc2015-08-24 02:16:19 -07004167 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
4168 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
4169 return n
4170}
4171
Keith Randall4a7aba72016-03-28 11:25:17 -07004172func (e *ssaExport) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4173 n := name.N.(*Node)
4174 ptrType := Ptrto(Types[TUINT8])
4175 lenType := Types[TINT]
4176 if n.Class == PAUTO && !n.Addrtaken {
4177 // Split this string up into two separate variables.
4178 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4179 l := e.namedAuto(n.Sym.Name+".len", lenType)
4180 return ssa.LocalSlot{p, ptrType, 0}, ssa.LocalSlot{l, lenType, 0}
4181 }
4182 // Return the two parts of the larger variable.
4183 return ssa.LocalSlot{n, ptrType, name.Off}, ssa.LocalSlot{n, lenType, name.Off + int64(Widthptr)}
4184}
4185
4186func (e *ssaExport) SplitInterface(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4187 n := name.N.(*Node)
4188 t := Ptrto(Types[TUINT8])
4189 if n.Class == PAUTO && !n.Addrtaken {
4190 // Split this interface up into two separate variables.
4191 f := ".itab"
Matthew Dempsky00e5a682016-04-01 13:36:24 -07004192 if n.Type.IsEmptyInterface() {
Keith Randall4a7aba72016-03-28 11:25:17 -07004193 f = ".type"
4194 }
4195 c := e.namedAuto(n.Sym.Name+f, t)
4196 d := e.namedAuto(n.Sym.Name+".data", t)
4197 return ssa.LocalSlot{c, t, 0}, ssa.LocalSlot{d, t, 0}
4198 }
4199 // Return the two parts of the larger variable.
4200 return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + int64(Widthptr)}
4201}
4202
4203func (e *ssaExport) SplitSlice(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot, ssa.LocalSlot) {
4204 n := name.N.(*Node)
4205 ptrType := Ptrto(n.Type.Type)
4206 lenType := Types[TINT]
4207 if n.Class == PAUTO && !n.Addrtaken {
4208 // Split this slice up into three separate variables.
4209 p := e.namedAuto(n.Sym.Name+".ptr", ptrType)
4210 l := e.namedAuto(n.Sym.Name+".len", lenType)
4211 c := e.namedAuto(n.Sym.Name+".cap", lenType)
4212 return ssa.LocalSlot{p, ptrType, 0}, ssa.LocalSlot{l, lenType, 0}, ssa.LocalSlot{c, lenType, 0}
4213 }
4214 // Return the three parts of the larger variable.
4215 return ssa.LocalSlot{n, ptrType, name.Off},
4216 ssa.LocalSlot{n, lenType, name.Off + int64(Widthptr)},
4217 ssa.LocalSlot{n, lenType, name.Off + int64(2*Widthptr)}
4218}
4219
4220func (e *ssaExport) SplitComplex(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
4221 n := name.N.(*Node)
4222 s := name.Type.Size() / 2
4223 var t *Type
4224 if s == 8 {
4225 t = Types[TFLOAT64]
4226 } else {
4227 t = Types[TFLOAT32]
4228 }
4229 if n.Class == PAUTO && !n.Addrtaken {
4230 // Split this complex up into two separate variables.
4231 c := e.namedAuto(n.Sym.Name+".real", t)
4232 d := e.namedAuto(n.Sym.Name+".imag", t)
4233 return ssa.LocalSlot{c, t, 0}, ssa.LocalSlot{d, t, 0}
4234 }
4235 // Return the two parts of the larger variable.
4236 return ssa.LocalSlot{n, t, name.Off}, ssa.LocalSlot{n, t, name.Off + s}
4237}
4238
4239// namedAuto returns a new AUTO variable with the given name and type.
4240func (e *ssaExport) namedAuto(name string, typ ssa.Type) ssa.GCNode {
4241 t := typ.(*Type)
4242 s := Lookup(name)
4243 n := Nod(ONAME, nil, nil)
4244 s.Def = n
4245 s.Def.Used = true
4246 n.Sym = s
4247 n.Type = t
4248 n.Class = PAUTO
4249 n.Addable = true
4250 n.Ullman = 1
4251 n.Esc = EscNever
4252 n.Xoffset = 0
4253 n.Name.Curfn = Curfn
4254 Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
4255
4256 dowidth(t)
4257 e.mustImplement = true
4258
4259 return n
4260}
4261
Keith Randall7d612462015-10-22 13:07:38 -07004262func (e *ssaExport) CanSSA(t ssa.Type) bool {
Keith Randall37590bd2015-09-18 22:58:10 -07004263 return canSSAType(t.(*Type))
4264}
4265
Keith Randallb5c5efd2016-01-14 16:02:23 -08004266func (e *ssaExport) Line(line int32) string {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08004267 return linestr(line)
Keith Randallb5c5efd2016-01-14 16:02:23 -08004268}
4269
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004270// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004271func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004272 // If e was marked as unimplemented, anything could happen. Ignore.
4273 if e.log && !e.unimplemented {
4274 fmt.Printf(msg, args...)
4275 }
4276}
4277
David Chase88b230e2016-01-29 14:44:15 -05004278func (e *ssaExport) Log() bool {
4279 return e.log
4280}
4281
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004282// Fatal reports a compiler error and exits.
Keith Randallda8af472016-01-13 11:14:57 -08004283func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004284 // If e was marked as unimplemented, anything could happen. Ignore.
4285 if !e.unimplemented {
Keith Randallda8af472016-01-13 11:14:57 -08004286 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004287 Fatalf(msg, args...)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004288 }
4289}
4290
4291// Unimplemented reports that the function cannot be compiled.
4292// It will be removed once SSA work is complete.
Keith Randallda8af472016-01-13 11:14:57 -08004293func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004294 if e.mustImplement {
Keith Randallda8af472016-01-13 11:14:57 -08004295 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004296 Fatalf(msg, args...)
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004297 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004298 const alwaysLog = false // enable to calculate top unimplemented features
4299 if !e.unimplemented && (e.log || alwaysLog) {
4300 // first implementation failure, print explanation
4301 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4302 }
4303 e.unimplemented = true
4304}
Keith Randallc24681a2015-10-22 14:22:38 -07004305
David Chase729abfa2015-10-26 17:34:06 -04004306// Warnl reports a "warning", which is usually flag-triggered
4307// logging output for the benefit of tests.
Todd Neal98b88de2016-03-13 23:04:31 -05004308func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
4309 Warnl(line, fmt_, args...)
David Chase729abfa2015-10-26 17:34:06 -04004310}
4311
4312func (e *ssaExport) Debug_checknil() bool {
4313 return Debug_checknil != 0
4314}
4315
Keith Randallc24681a2015-10-22 14:22:38 -07004316func (n *Node) Typ() ssa.Type {
4317 return n.Type
4318}